// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdint.h>

#include <list>

#include "base/command_line.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/timer/timer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/env.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/hit_test.h"
#include "ui/base/ui_base_switches.h"
#include "ui/events/event.h"
#include "ui/events/event_switches.h"
#include "ui/events/event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/gestures/gesture_recognizer_impl.h"
#include "ui/events/gestures/gesture_types.h"
#include "ui/events/test/event_generator.h"
#include "ui/events/test/events_test_utils.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"

namespace aura {
namespace test {

    namespace {

        std::string WindowIDAsString(ui::GestureConsumer* consumer)
        {
            return consumer ? base::IntToString(static_cast<Window*>(consumer)->id()) : "?";
        }

#define EXPECT_0_EVENTS(events) \
    EXPECT_EQ(0u, events.size())

#define EXPECT_1_EVENT(events, e0) \
    EXPECT_EQ(1u, events.size());  \
    EXPECT_EQ(e0, events[0])

#define EXPECT_2_EVENTS(events, e0, e1) \
    EXPECT_EQ(2u, events.size());       \
    EXPECT_EQ(e0, events[0]);           \
    EXPECT_EQ(e1, events[1])

#define EXPECT_3_EVENTS(events, e0, e1, e2) \
    EXPECT_EQ(3u, events.size());           \
    EXPECT_EQ(e0, events[0]);               \
    EXPECT_EQ(e1, events[1]);               \
    EXPECT_EQ(e2, events[2])

#define EXPECT_4_EVENTS(events, e0, e1, e2, e3) \
    EXPECT_EQ(4u, events.size());               \
    EXPECT_EQ(e0, events[0]);                   \
    EXPECT_EQ(e1, events[1]);                   \
    EXPECT_EQ(e2, events[2]);                   \
    EXPECT_EQ(e3, events[3])

        // A delegate that keeps track of gesture events.
        class GestureEventConsumeDelegate : public TestWindowDelegate {
        public:
            GestureEventConsumeDelegate()
                : tap_(false)
                , tap_down_(false)
                , tap_cancel_(false)
                , begin_(false)
                , end_(false)
                , scroll_begin_(false)
                , scroll_update_(false)
                , scroll_end_(false)
                , pinch_begin_(false)
                , pinch_update_(false)
                , pinch_end_(false)
                , long_press_(false)
                , fling_(false)
                , two_finger_tap_(false)
                , show_press_(false)
                , swipe_left_(false)
                , swipe_right_(false)
                , swipe_up_(false)
                , swipe_down_(false)
                , scroll_x_(0)
                , scroll_y_(0)
                , scroll_velocity_x_(0)
                , scroll_velocity_y_(0)
                , velocity_x_(0)
                , velocity_y_(0)
                , scroll_x_hint_(0)
                , scroll_y_hint_(0)
                , tap_count_(0)
                , flags_(0)
                , wait_until_event_(ui::ET_UNKNOWN)
            {
            }

            ~GestureEventConsumeDelegate() override { }

            void Reset()
            {
                events_.clear();
                tap_ = false;
                tap_down_ = false;
                tap_cancel_ = false;
                begin_ = false;
                end_ = false;
                scroll_begin_ = false;
                scroll_update_ = false;
                scroll_end_ = false;
                pinch_begin_ = false;
                pinch_update_ = false;
                pinch_end_ = false;
                long_press_ = false;
                fling_ = false;
                two_finger_tap_ = false;
                show_press_ = false;
                swipe_left_ = false;
                swipe_right_ = false;
                swipe_up_ = false;
                swipe_down_ = false;

                scroll_begin_position_.SetPoint(0, 0);
                tap_location_.SetPoint(0, 0);
                gesture_end_location_.SetPoint(0, 0);

                scroll_x_ = 0;
                scroll_y_ = 0;
                scroll_velocity_x_ = 0;
                scroll_velocity_y_ = 0;
                velocity_x_ = 0;
                velocity_y_ = 0;
                scroll_x_hint_ = 0;
                scroll_y_hint_ = 0;
                tap_count_ = 0;
                scale_ = 0;
                flags_ = 0;
            }

            const std::vector<ui::EventType>& events() const { return events_; };

            bool tap() const { return tap_; }
            bool tap_down() const { return tap_down_; }
            bool tap_cancel() const { return tap_cancel_; }
            bool begin() const { return begin_; }
            bool end() const { return end_; }
            bool scroll_begin() const { return scroll_begin_; }
            bool scroll_update() const { return scroll_update_; }
            bool scroll_end() const { return scroll_end_; }
            bool pinch_begin() const { return pinch_begin_; }
            bool pinch_update() const { return pinch_update_; }
            bool pinch_end() const { return pinch_end_; }
            bool long_press() const { return long_press_; }
            bool long_tap() const { return long_tap_; }
            bool fling() const { return fling_; }
            bool two_finger_tap() const { return two_finger_tap_; }
            bool show_press() const { return show_press_; }
            bool swipe_left() const { return swipe_left_; }
            bool swipe_right() const { return swipe_right_; }
            bool swipe_up() const { return swipe_up_; }
            bool swipe_down() const { return swipe_down_; }

            const gfx::Point& scroll_begin_position() const
            {
                return scroll_begin_position_;
            }

            const gfx::Point& tap_location() const
            {
                return tap_location_;
            }

            const gfx::Point& gesture_end_location() const
            {
                return gesture_end_location_;
            }

            float scroll_x() const { return scroll_x_; }
            float scroll_y() const { return scroll_y_; }
            float scroll_velocity_x() const { return scroll_velocity_x_; }
            float scroll_velocity_y() const { return scroll_velocity_y_; }
            float velocity_x() const { return velocity_x_; }
            float velocity_y() const { return velocity_y_; }
            float scroll_x_hint() const { return scroll_x_hint_; }
            float scroll_y_hint() const { return scroll_y_hint_; }
            float scale() const { return scale_; }
            const gfx::Rect& bounding_box() const { return bounding_box_; }
            int tap_count() const { return tap_count_; }
            int flags() const { return flags_; }

            void WaitUntilReceivedGesture(ui::EventType type)
            {
                wait_until_event_ = type;
                run_loop_.reset(new base::RunLoop());
                run_loop_->Run();
            }

            void OnGestureEvent(ui::GestureEvent* gesture) override
            {
                events_.push_back(gesture->type());
                bounding_box_ = gesture->details().bounding_box();
                flags_ = gesture->flags();
                switch (gesture->type()) {
                case ui::ET_GESTURE_TAP:
                    tap_location_ = gesture->location();
                    tap_count_ = gesture->details().tap_count();
                    tap_ = true;
                    break;
                case ui::ET_GESTURE_TAP_DOWN:
                    tap_down_ = true;
                    break;
                case ui::ET_GESTURE_TAP_CANCEL:
                    tap_cancel_ = true;
                    break;
                case ui::ET_GESTURE_BEGIN:
                    begin_ = true;
                    break;
                case ui::ET_GESTURE_END:
                    end_ = true;
                    gesture_end_location_ = gesture->location();
                    break;
                case ui::ET_GESTURE_SCROLL_BEGIN:
                    scroll_begin_ = true;
                    scroll_begin_position_ = gesture->location();
                    scroll_x_hint_ = gesture->details().scroll_x_hint();
                    scroll_y_hint_ = gesture->details().scroll_y_hint();
                    break;
                case ui::ET_GESTURE_SCROLL_UPDATE:
                    scroll_update_ = true;
                    scroll_x_ += gesture->details().scroll_x();
                    scroll_y_ += gesture->details().scroll_y();
                    break;
                case ui::ET_GESTURE_SCROLL_END:
                    EXPECT_TRUE(velocity_x_ == 0 && velocity_y_ == 0);
                    scroll_end_ = true;
                    break;
                case ui::ET_GESTURE_PINCH_BEGIN:
                    pinch_begin_ = true;
                    break;
                case ui::ET_GESTURE_PINCH_UPDATE:
                    pinch_update_ = true;
                    scale_ = gesture->details().scale();
                    break;
                case ui::ET_GESTURE_PINCH_END:
                    pinch_end_ = true;
                    break;
                case ui::ET_GESTURE_LONG_PRESS:
                    long_press_ = true;
                    break;
                case ui::ET_GESTURE_LONG_TAP:
                    long_tap_ = true;
                    break;
                case ui::ET_SCROLL_FLING_START:
                    EXPECT_TRUE(gesture->details().velocity_x() != 0 || gesture->details().velocity_y() != 0);
                    EXPECT_FALSE(scroll_end_);
                    fling_ = true;
                    velocity_x_ = gesture->details().velocity_x();
                    velocity_y_ = gesture->details().velocity_y();
                    break;
                case ui::ET_GESTURE_TWO_FINGER_TAP:
                    two_finger_tap_ = true;
                    break;
                case ui::ET_GESTURE_SHOW_PRESS:
                    show_press_ = true;
                    break;
                case ui::ET_GESTURE_SWIPE:
                    swipe_left_ = gesture->details().swipe_left();
                    swipe_right_ = gesture->details().swipe_right();
                    swipe_up_ = gesture->details().swipe_up();
                    swipe_down_ = gesture->details().swipe_down();
                    break;
                case ui::ET_SCROLL_FLING_CANCEL:
                    // Only used in unified gesture detection.
                    break;
                default:
                    NOTREACHED();
                }
                if (wait_until_event_ == gesture->type() && run_loop_) {
                    run_loop_->Quit();
                    wait_until_event_ = ui::ET_UNKNOWN;
                }
                gesture->StopPropagation();
            }

        private:
            scoped_ptr<base::RunLoop> run_loop_;
            std::vector<ui::EventType> events_;

            bool tap_;
            bool tap_down_;
            bool tap_cancel_;
            bool begin_;
            bool end_;
            bool scroll_begin_;
            bool scroll_update_;
            bool scroll_end_;
            bool pinch_begin_;
            bool pinch_update_;
            bool pinch_end_;
            bool long_press_;
            bool long_tap_;
            bool fling_;
            bool two_finger_tap_;
            bool show_press_;
            bool swipe_left_;
            bool swipe_right_;
            bool swipe_up_;
            bool swipe_down_;

            gfx::Point scroll_begin_position_;
            gfx::Point tap_location_;
            gfx::Point gesture_end_location_;

            float scroll_x_;
            float scroll_y_;
            float scroll_velocity_x_;
            float scroll_velocity_y_;
            float velocity_x_;
            float velocity_y_;
            float scroll_x_hint_;
            float scroll_y_hint_;
            float scale_;
            gfx::Rect bounding_box_;
            int tap_count_;
            int flags_;

            ui::EventType wait_until_event_;

            DISALLOW_COPY_AND_ASSIGN(GestureEventConsumeDelegate);
        };

        class QueueTouchEventDelegate : public GestureEventConsumeDelegate {
        public:
            explicit QueueTouchEventDelegate(WindowEventDispatcher* dispatcher)
                : window_(NULL)
                , dispatcher_(dispatcher)
                , synchronous_ack_for_next_event_(AckState::PENDING)
            {
            }

            ~QueueTouchEventDelegate() override { }

            void OnTouchEvent(ui::TouchEvent* event) override
            {
                event->DisableSynchronousHandling();
                if (synchronous_ack_for_next_event_ != AckState::PENDING) {
                    ui::GestureRecognizer::Get()->AckTouchEvent(
                        event->unique_event_id(),
                        synchronous_ack_for_next_event_ == AckState::CONSUMED
                            ? ui::ER_CONSUMED
                            : ui::ER_UNHANDLED,
                        window_);
                    synchronous_ack_for_next_event_ = AckState::PENDING;
                } else {
                    sent_events_ids_.push_back(event->unique_event_id());
                }
            }

            void ReceivedAck()
            {
                ReceivedAckImpl(false);
            }

            void ReceivedAckPreventDefaulted()
            {
                ReceivedAckImpl(true);
            }

            void set_window(Window* w) { window_ = w; }
            void set_synchronous_ack_for_next_event(bool consumed)
            {
                DCHECK(synchronous_ack_for_next_event_ == AckState::PENDING);
                synchronous_ack_for_next_event_ = consumed ? AckState::CONSUMED : AckState::UNCONSUMED;
            }

        private:
            enum class AckState {
                PENDING,
                CONSUMED,
                UNCONSUMED,
            };

            void ReceivedAckImpl(bool prevent_defaulted)
            {
                DCHECK(!sent_events_ids_.empty());
                if (sent_events_ids_.empty())
                    return;
                uint32_t sent_event_id = sent_events_ids_.front();
                sent_events_ids_.pop_front();
                dispatcher_->ProcessedTouchEvent(
                    sent_event_id, window_,
                    prevent_defaulted ? ui::ER_HANDLED : ui::ER_UNHANDLED);
            }

            Window* window_;
            WindowEventDispatcher* dispatcher_;
            AckState synchronous_ack_for_next_event_;
            std::list<uint32_t> sent_events_ids_;

            DISALLOW_COPY_AND_ASSIGN(QueueTouchEventDelegate);
        };

        // A delegate that ignores gesture events but keeps track of [synthetic] mouse
        // events.
        class GestureEventSynthDelegate : public TestWindowDelegate {
        public:
            GestureEventSynthDelegate()
                : mouse_enter_(false)
                , mouse_exit_(false)
                , mouse_press_(false)
                , mouse_release_(false)
                , mouse_move_(false)
                , double_click_(false)
            {
            }

            void Reset()
            {
                mouse_enter_ = false;
                mouse_exit_ = false;
                mouse_press_ = false;
                mouse_release_ = false;
                mouse_move_ = false;
                double_click_ = false;
            }

            bool mouse_enter() const { return mouse_enter_; }
            bool mouse_exit() const { return mouse_exit_; }
            bool mouse_press() const { return mouse_press_; }
            bool mouse_move() const { return mouse_move_; }
            bool mouse_release() const { return mouse_release_; }
            bool double_click() const { return double_click_; }

            void OnMouseEvent(ui::MouseEvent* event) override
            {
                switch (event->type()) {
                case ui::ET_MOUSE_PRESSED:
                    double_click_ = event->flags() & ui::EF_IS_DOUBLE_CLICK;
                    mouse_press_ = true;
                    break;
                case ui::ET_MOUSE_RELEASED:
                    mouse_release_ = true;
                    break;
                case ui::ET_MOUSE_MOVED:
                    mouse_move_ = true;
                    break;
                case ui::ET_MOUSE_ENTERED:
                    mouse_enter_ = true;
                    break;
                case ui::ET_MOUSE_EXITED:
                    mouse_exit_ = true;
                    break;
                default:
                    NOTREACHED();
                }
                event->SetHandled();
            }

        private:
            bool mouse_enter_;
            bool mouse_exit_;
            bool mouse_press_;
            bool mouse_release_;
            bool mouse_move_;
            bool double_click_;

            DISALLOW_COPY_AND_ASSIGN(GestureEventSynthDelegate);
        };

        class ScopedGestureRecognizerSetter {
        public:
            // Takes ownership of |new_gr|.
            explicit ScopedGestureRecognizerSetter(ui::GestureRecognizer* new_gr)
                : new_gr_(new_gr)
            {
                original_gr_ = ui::GestureRecognizer::Get();
                ui::SetGestureRecognizerForTesting(new_gr_.get());
            }

            virtual ~ScopedGestureRecognizerSetter()
            {
                ui::SetGestureRecognizerForTesting(original_gr_);
            }

        private:
            ui::GestureRecognizer* original_gr_;
            scoped_ptr<ui::GestureRecognizer> new_gr_;

            DISALLOW_COPY_AND_ASSIGN(ScopedGestureRecognizerSetter);
        };

        class TimedEvents {
        private:
            int simulated_now_;

        public:
            // Use a non-zero start time to pass DCHECKs which ensure events have had a
            // time assigned.
            TimedEvents()
                : simulated_now_(1)
            {
            }

            base::TimeDelta Now()
            {
                base::TimeDelta t = base::TimeDelta::FromMilliseconds(simulated_now_);
                simulated_now_++;
                return t;
            }

            base::TimeDelta LeapForward(int time_in_millis)
            {
                simulated_now_ += time_in_millis;
                return base::TimeDelta::FromMilliseconds(simulated_now_);
            }

            base::TimeDelta InFuture(int time_in_millis)
            {
                return base::TimeDelta::FromMilliseconds(simulated_now_ + time_in_millis);
            }

            void SendScrollEvents(ui::EventProcessor* dispatcher,
                int x_start,
                int y_start,
                int dx,
                int dy,
                int touch_id,
                int time_step,
                int num_steps,
                GestureEventConsumeDelegate* delegate)
            {
                float x = x_start;
                float y = y_start;

                for (int i = 0; i < num_steps; i++) {
                    x += dx;
                    y += dy;
                    ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(x, y), touch_id,
                        base::TimeDelta::FromMilliseconds(simulated_now_));
                    ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move);
                    ASSERT_FALSE(details.dispatcher_destroyed);
                    simulated_now_ += time_step;
                }
            }

            void SendScrollEvent(ui::EventProcessor* dispatcher,
                float x,
                float y,
                int touch_id,
                GestureEventConsumeDelegate* delegate)
            {
                delegate->Reset();
                ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(), touch_id,
                    base::TimeDelta::FromMilliseconds(simulated_now_));
                move.set_location_f(gfx::PointF(x, y));
                move.set_root_location_f(gfx::PointF(x, y));
                ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move);
                ASSERT_FALSE(details.dispatcher_destroyed);
                simulated_now_++;
            }
        };

        // An event handler to keep track of events.
        class TestEventHandler : public ui::EventHandler {
        public:
            TestEventHandler()
                : touch_released_count_(0)
                , touch_pressed_count_(0)
                , touch_moved_count_(0)
            {
            }

            ~TestEventHandler() override { }

            void OnTouchEvent(ui::TouchEvent* event) override
            {
                switch (event->type()) {
                case ui::ET_TOUCH_RELEASED:
                    touch_released_count_++;
                    break;
                case ui::ET_TOUCH_PRESSED:
                    touch_pressed_count_++;
                    break;
                case ui::ET_TOUCH_MOVED:
                    touch_moved_count_++;
                    break;
                case ui::ET_TOUCH_CANCELLED:
                    cancelled_touch_points_.push_back(event->location_f());
                    break;
                default:
                    break;
                }
            }

            void Reset()
            {
                touch_released_count_ = 0;
                touch_pressed_count_ = 0;
                touch_moved_count_ = 0;
                cancelled_touch_points_.clear();
            }

            int touch_released_count() const { return touch_released_count_; }
            int touch_pressed_count() const { return touch_pressed_count_; }
            int touch_moved_count() const { return touch_moved_count_; }
            int touch_cancelled_count() const
            {
                return static_cast<int>(cancelled_touch_points_.size());
            }
            const std::vector<gfx::PointF>& cancelled_touch_points() const
            {
                return cancelled_touch_points_;
            }

        private:
            int touch_released_count_;
            int touch_pressed_count_;
            int touch_moved_count_;
            std::vector<gfx::PointF> cancelled_touch_points_;

            DISALLOW_COPY_AND_ASSIGN(TestEventHandler);
        };

        // Removes the target window from its parent when it receives a touch-cancel
        // event.
        class RemoveOnTouchCancelHandler : public TestEventHandler {
        public:
            RemoveOnTouchCancelHandler() { }
            ~RemoveOnTouchCancelHandler() override { }

        private:
            // ui::EventHandler:
            void OnTouchEvent(ui::TouchEvent* event) override
            {
                TestEventHandler::OnTouchEvent(event);
                if (event->type() == ui::ET_TOUCH_CANCELLED) {
                    Window* target = static_cast<Window*>(event->target());
                    target->parent()->RemoveChild(target);
                }
            }

            DISALLOW_COPY_AND_ASSIGN(RemoveOnTouchCancelHandler);
        };

        void DelayByLongPressTimeout()
        {
            ui::GestureProvider::Config config;
            base::RunLoop run_loop;
            base::MessageLoop::current()->PostDelayedTask(
                FROM_HERE,
                run_loop.QuitClosure(),
                config.gesture_detector_config.longpress_timeout * 2);
            run_loop.Run();
        }

        void DelayByShowPressTimeout()
        {
            ui::GestureProvider::Config config;
            base::RunLoop run_loop;
            base::MessageLoop::current()->PostDelayedTask(
                FROM_HERE,
                run_loop.QuitClosure(),
                config.gesture_detector_config.showpress_timeout * 2);
            run_loop.Run();
        }

        void SetTouchRadius(ui::TouchEvent* event, float radius_x, float radius_y)
        {
            // Using ctor (over direct struct access) due to it's special behavior with
            // radii.
            ui::PointerDetails details(ui::EventPointerType::POINTER_TYPE_TOUCH,
                radius_x,
                radius_y,
                event->pointer_details().force,
                event->pointer_details().tilt_x,
                event->pointer_details().tilt_y);
            event->set_pointer_details(details);
        }

    } // namespace

    class GestureRecognizerTest : public AuraTestBase,
                                  public ::testing::WithParamInterface<bool> {
    public:
        GestureRecognizerTest() { }

        void SetUp() override
        {
            AuraTestBase::SetUp();
            ui::GestureConfiguration::GetInstance()->set_show_press_delay_in_ms(2);
            ui::GestureConfiguration::GetInstance()->set_long_press_time_in_ms(3);
        }

    private:
        DISALLOW_COPY_AND_ASSIGN(GestureRecognizerTest);
    };

    class GestureRecognizerWithSwitchTest : public GestureRecognizerTest {
    public:
        GestureRecognizerWithSwitchTest() { }

        void SetUp() override
        {
            GestureRecognizerTest::SetUp();
            base::CommandLine::ForCurrentProcess()->AppendSwitch(
                switches::kCompensateForUnstablePinchZoom);
            ui::GestureConfiguration::GetInstance()->set_min_pinch_update_span_delta(5);
        }

    private:
        DISALLOW_COPY_AND_ASSIGN(GestureRecognizerWithSwitchTest);
    };

    // Check that appropriate touch events generate tap gesture events.
    TEST_F(GestureRecognizerTest, GestureEventTap)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 2;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->show_press());
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_TRUE(delegate->begin());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_FALSE(delegate->long_press());

        delegate->Reset();
        delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_SHOW_PRESS);
        EXPECT_TRUE(delegate->show_press());
        EXPECT_FALSE(delegate->tap_down());

        // Make sure there is enough delay before the touch is released so that it is
        // recognized as a tap.
        delegate->Reset();
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.LeapForward(50));

        DispatchEventUsingWindowDispatcher(&release);
        EXPECT_TRUE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->begin());
        EXPECT_TRUE(delegate->end());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());

        EXPECT_EQ(1, delegate->tap_count());
    }

    // Check that appropriate touch events generate tap gesture events
    // when information about the touch radii are provided.
    TEST_F(GestureRecognizerTest, GestureEventTapRegion)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 800;
        const int kWindowHeight = 600;
        const int kTouchId = 2;
        gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        // Test with no ET_TOUCH_MOVED events.
        {
            delegate->Reset();
            ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
                kTouchId, tes.Now());
            SetTouchRadius(&press, 5, 12);
            DispatchEventUsingWindowDispatcher(&press);
            EXPECT_FALSE(delegate->tap());
            EXPECT_TRUE(delegate->tap_down());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_TRUE(delegate->begin());
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());
            EXPECT_FALSE(delegate->long_press());

            // Make sure there is enough delay before the touch is released so that it
            // is recognized as a tap.
            delegate->Reset();
            ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
                kTouchId, tes.LeapForward(50));
            SetTouchRadius(&release, 5, 12);

            DispatchEventUsingWindowDispatcher(&release);
            EXPECT_TRUE(delegate->tap());
            EXPECT_FALSE(delegate->tap_down());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_FALSE(delegate->begin());
            EXPECT_TRUE(delegate->end());
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());

            EXPECT_EQ(1, delegate->tap_count());
            gfx::Point actual_point(delegate->tap_location());
            EXPECT_EQ(24, delegate->bounding_box().width());
            EXPECT_EQ(24, delegate->bounding_box().height());
            EXPECT_EQ(101, actual_point.x());
            EXPECT_EQ(201, actual_point.y());
        }

        // Test with no ET_TOUCH_MOVED events but different touch points and radii.
        {
            delegate->Reset();
            ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(365, 290),
                kTouchId, tes.Now());
            SetTouchRadius(&press, 8, 14);
            DispatchEventUsingWindowDispatcher(&press);
            EXPECT_FALSE(delegate->tap());
            EXPECT_TRUE(delegate->tap_down());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_TRUE(delegate->begin());
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());
            EXPECT_FALSE(delegate->long_press());

            delegate->Reset();
            ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(367, 291),
                kTouchId, tes.LeapForward(50));
            SetTouchRadius(&release, 20, 13);

            DispatchEventUsingWindowDispatcher(&release);
            EXPECT_TRUE(delegate->tap());
            EXPECT_FALSE(delegate->tap_down());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_FALSE(delegate->begin());
            EXPECT_TRUE(delegate->end());
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());

            EXPECT_EQ(1, delegate->tap_count());
            gfx::Point actual_point(delegate->tap_location());
            EXPECT_EQ(40, delegate->bounding_box().width());
            EXPECT_EQ(40, delegate->bounding_box().height());
            EXPECT_EQ(367, actual_point.x());
            EXPECT_EQ(291, actual_point.y());
        }

        // Test with a single ET_TOUCH_MOVED event.
        {
            delegate->Reset();
            ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(46, 205),
                kTouchId, tes.Now());
            SetTouchRadius(&press, 6, 10);
            DispatchEventUsingWindowDispatcher(&press);
            EXPECT_FALSE(delegate->tap());
            EXPECT_TRUE(delegate->tap_down());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_TRUE(delegate->begin());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());
            EXPECT_FALSE(delegate->long_press());

            delegate->Reset();
            ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(49, 204),
                kTouchId, tes.LeapForward(50));
            SetTouchRadius(&move, 8, 12);
            DispatchEventUsingWindowDispatcher(&move);
            EXPECT_FALSE(delegate->tap());
            EXPECT_FALSE(delegate->tap_down());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_FALSE(delegate->begin());
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());
            EXPECT_FALSE(delegate->long_press());

            delegate->Reset();
            ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(49, 204),
                kTouchId, tes.LeapForward(50));
            SetTouchRadius(&release, 4, 8);

            DispatchEventUsingWindowDispatcher(&release);
            EXPECT_TRUE(delegate->tap());
            EXPECT_FALSE(delegate->tap_down());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_FALSE(delegate->begin());
            EXPECT_TRUE(delegate->end());
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());

            EXPECT_EQ(1, delegate->tap_count());
            gfx::Point actual_point(delegate->tap_location());
            EXPECT_EQ(16, delegate->bounding_box().width());
            EXPECT_EQ(16, delegate->bounding_box().height());
            EXPECT_EQ(49, actual_point.x());
            EXPECT_EQ(204, actual_point.y());
        }

        // Test with a few ET_TOUCH_MOVED events.
        {
            delegate->Reset();
            ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(400, 150),
                kTouchId, tes.Now());
            SetTouchRadius(&press, 7, 10);
            DispatchEventUsingWindowDispatcher(&press);
            EXPECT_FALSE(delegate->tap());
            EXPECT_TRUE(delegate->tap_down());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_TRUE(delegate->begin());
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());
            EXPECT_FALSE(delegate->long_press());

            delegate->Reset();
            ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(397, 151),
                kTouchId, tes.LeapForward(50));
            SetTouchRadius(&move, 13, 12);
            DispatchEventUsingWindowDispatcher(&move);
            EXPECT_FALSE(delegate->tap());
            EXPECT_FALSE(delegate->tap_down());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_FALSE(delegate->begin());
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());
            EXPECT_FALSE(delegate->long_press());

            delegate->Reset();
            ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(397, 149),
                kTouchId, tes.LeapForward(50));
            SetTouchRadius(&move1, 16, 16);
            DispatchEventUsingWindowDispatcher(&move1);
            EXPECT_FALSE(delegate->tap());
            EXPECT_FALSE(delegate->tap_down());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_FALSE(delegate->begin());
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());
            EXPECT_FALSE(delegate->long_press());

            delegate->Reset();
            ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(400, 150),
                kTouchId, tes.LeapForward(50));
            SetTouchRadius(&move2, 14, 10);
            DispatchEventUsingWindowDispatcher(&move2);
            EXPECT_FALSE(delegate->tap());
            EXPECT_FALSE(delegate->tap_down());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_FALSE(delegate->begin());
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());
            EXPECT_FALSE(delegate->long_press());

            delegate->Reset();
            ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(401, 149),
                kTouchId, tes.LeapForward(50));
            SetTouchRadius(&release, 8, 9);

            DispatchEventUsingWindowDispatcher(&release);
            EXPECT_TRUE(delegate->tap());
            EXPECT_FALSE(delegate->tap_down());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_FALSE(delegate->begin());
            EXPECT_TRUE(delegate->end());
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());

            EXPECT_EQ(1, delegate->tap_count());
            gfx::Point actual_point(delegate->tap_location());
            EXPECT_EQ(18, delegate->bounding_box().width());
            EXPECT_EQ(18, delegate->bounding_box().height());
            EXPECT_EQ(401, actual_point.x());
            EXPECT_EQ(149, actual_point.y());
        }
    }

    // Check that appropriate touch events generate scroll gesture events.
    TEST_F(GestureRecognizerTest, GestureEventScroll)
    {
        // We'll start by moving the touch point by (10.5, 10.5). We want 5 dips of
        // that distance to be consumed by the slop, so we set the slop radius to
        // sqrt(5 * 5 + 5 * 5).
        ui::GestureConfiguration::GetInstance()
            ->set_max_touch_move_in_pixels_for_click(sqrt(5.f * 5 + 5 * 5));
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 5;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_GESTURE_BEGIN,
            ui::ET_GESTURE_TAP_DOWN);

        // Move the touch-point enough so that it is considered as a scroll. This
        // should generate both SCROLL_BEGIN and SCROLL_UPDATE gestures.
        // The first movement is diagonal, to ensure that we have a free scroll,
        // and not a rail scroll.
        tes.SendScrollEvent(event_processor(), 111.5, 211.5, kTouchId,
            delegate.get());
        EXPECT_3_EVENTS(delegate->events(),
            ui::ET_GESTURE_TAP_CANCEL,
            ui::ET_GESTURE_SCROLL_BEGIN,
            ui::ET_GESTURE_SCROLL_UPDATE);
        // The slop consumed 5 dips
        EXPECT_FLOAT_EQ(5.5, delegate->scroll_x());
        EXPECT_FLOAT_EQ(5.5, delegate->scroll_y());
        EXPECT_EQ(gfx::Point(1, 1).ToString(),
            delegate->scroll_begin_position().ToString());

        // When scrolling with a single finger, the bounding box of the gesture should
        // be empty, since it's a single point and the radius for testing is zero.
        EXPECT_TRUE(delegate->bounding_box().IsEmpty());

        // Move some more to generate a few more scroll updates. Make sure that we get
        // out of the snap channel for the unified GR.
        tes.SendScrollEvent(event_processor(), 20, 120, kTouchId, delegate.get());
        EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
        EXPECT_FLOAT_EQ(-91.5, delegate->scroll_x());
        EXPECT_FLOAT_EQ(-91.5, delegate->scroll_y());
        EXPECT_TRUE(delegate->bounding_box().IsEmpty());

        tes.SendScrollEvent(event_processor(), 50, 124, kTouchId, delegate.get());
        EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
        EXPECT_EQ(30, delegate->scroll_x());
        EXPECT_EQ(4, delegate->scroll_y());
        EXPECT_TRUE(delegate->bounding_box().IsEmpty());

        // Release the touch. This should end the scroll.
        delegate->Reset();
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId,
            tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release);
        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_SCROLL_FLING_START,
            ui::ET_GESTURE_END);
        EXPECT_TRUE(delegate->bounding_box().IsEmpty());
    }

    // Check that predicted scroll update positions are correct.
    TEST_F(GestureRecognizerTest, GestureEventScrollPrediction)
    {
        // We'll start by moving the touch point by (5, 5). We want all of that
        // distance to be consumed by the slop, so we set the slop radius to
        // sqrt(5 * 5 + 5 * 5).
        ui::GestureConfiguration::GetInstance()
            ->set_max_touch_move_in_pixels_for_click(sqrt(5.f * 5 + 5 * 5));

        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 5;
        gfx::Rect bounds(95, 195, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();
        // Tracks the total scroll since we want to verify that the correct position
        // will be scrolled to throughout the prediction.
        gfx::Vector2dF total_scroll;
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(96, 196),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_GESTURE_BEGIN,
            ui::ET_GESTURE_TAP_DOWN);
        delegate->Reset();

        // Get rid of touch slop.
        ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(111, 211),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&move);
        EXPECT_3_EVENTS(delegate->events(),
            ui::ET_GESTURE_TAP_CANCEL,
            ui::ET_GESTURE_SCROLL_BEGIN,
            ui::ET_GESTURE_SCROLL_UPDATE);
        total_scroll.set_x(total_scroll.x() + delegate->scroll_x());
        total_scroll.set_y(total_scroll.y() + delegate->scroll_y());

        // Move the touch-point enough so that it is considered as a scroll. This
        // should generate both SCROLL_BEGIN and SCROLL_UPDATE gestures.
        // The first movement is diagonal, to ensure that we have a free scroll,
        // and not a rail scroll.
        tes.LeapForward(30);
        tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());
        EXPECT_1_EVENT(delegate->events(),
            ui::ET_GESTURE_SCROLL_UPDATE);
        total_scroll.set_x(total_scroll.x() + delegate->scroll_x());
        total_scroll.set_y(total_scroll.y() + delegate->scroll_y());

        // Move some more to generate a few more scroll updates.
        tes.LeapForward(30);
        tes.SendScrollEvent(event_processor(), 110, 211, kTouchId, delegate.get());
        EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
        total_scroll.set_x(total_scroll.x() + delegate->scroll_x());
        total_scroll.set_y(total_scroll.y() + delegate->scroll_y());

        tes.LeapForward(30);
        tes.SendScrollEvent(event_processor(), 140, 215, kTouchId, delegate.get());
        EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
        total_scroll.set_x(total_scroll.x() + delegate->scroll_x());
        total_scroll.set_y(total_scroll.y() + delegate->scroll_y());

        // Release the touch. This should end the scroll.
        delegate->Reset();
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId,
            tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release);
    }

    // Check that the bounding box during a scroll event is correct.
    TEST_F(GestureRecognizerTest, GestureEventScrollBoundingBox)
    {
        TimedEvents tes;
        for (int radius = 1; radius <= 10; ++radius) {
            ui::GestureConfiguration::GetInstance()->set_default_radius(radius);
            scoped_ptr<GestureEventConsumeDelegate> delegate(
                new GestureEventConsumeDelegate());
            const int kWindowWidth = 123;
            const int kWindowHeight = 45;
            const int kTouchId = 5;
            gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
            scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
                delegate.get(), -1234, bounds, root_window()));

            const int kPositionX = 101;
            const int kPositionY = 201;
            delegate->Reset();
            ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
                gfx::Point(kPositionX, kPositionY), kTouchId,
                tes.Now());
            DispatchEventUsingWindowDispatcher(&press);
            EXPECT_EQ(gfx::Rect(kPositionX - radius, kPositionY - radius, radius * 2,
                          radius * 2),
                delegate->bounding_box());

            const int kScrollAmount = 50;
            tes.SendScrollEvents(event_processor(), kPositionX, kPositionY,
                1, 1, kTouchId, 1, kScrollAmount, delegate.get());
            EXPECT_EQ(gfx::Point(1, 1).ToString(),
                delegate->scroll_begin_position().ToString());
            EXPECT_EQ(
                gfx::Rect(kPositionX + kScrollAmount - radius,
                    kPositionY + kScrollAmount - radius, radius * 2, radius * 2),
                delegate->bounding_box());

            // Release the touch. This should end the scroll.
            delegate->Reset();
            ui::TouchEvent release(
                ui::ET_TOUCH_RELEASED,
                gfx::Point(kPositionX + kScrollAmount, kPositionY + kScrollAmount),
                kTouchId, press.time_stamp() + base::TimeDelta::FromMilliseconds(50));
            DispatchEventUsingWindowDispatcher(&release);
            EXPECT_EQ(
                gfx::Rect(kPositionX + kScrollAmount - radius,
                    kPositionY + kScrollAmount - radius, radius * 2, radius * 2),
                delegate->bounding_box());
        }
        ui::GestureConfiguration::GetInstance()->set_default_radius(0);
    }

    // Check Scroll End Events report correct velocities
    // if the user was on a horizontal rail
    TEST_F(GestureRecognizerTest, GestureEventHorizontalRailFling)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kTouchId = 7;
        gfx::Rect bounds(0, 0, 1000, 1000);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);

        // Get rid of touch slop.
        ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(10, 0),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&move);
        delegate->Reset();

        // Move the touch-point horizontally enough that it is considered a
        // horizontal scroll.
        tes.SendScrollEvent(event_processor(), 30, 1, kTouchId, delegate.get());
        EXPECT_FLOAT_EQ(0, delegate->scroll_y());
        EXPECT_FLOAT_EQ(20, delegate->scroll_x());

        // Get a high x velocity, while still staying on the rail
        const int kScrollAmount = 8;
        tes.SendScrollEvents(event_processor(),
            1,
            1,
            100,
            10,
            kTouchId,
            1,
            kScrollAmount,
            delegate.get());

        delegate->Reset();
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&release);

        EXPECT_TRUE(delegate->fling());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_GT(delegate->velocity_x(), 0);
        EXPECT_EQ(0, delegate->velocity_y());
    }

    // Check Scroll End Events report correct velocities
    // if the user was on a vertical rail
    TEST_F(GestureRecognizerTest, GestureEventVerticalRailFling)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kTouchId = 7;
        gfx::Rect bounds(0, 0, 1000, 1000);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);

        // Get rid of touch slop.
        ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(0, 10),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&move);
        delegate->Reset();

        // Move the touch-point vertically enough that it is considered a
        // vertical scroll.
        tes.SendScrollEvent(event_processor(), 1, 30, kTouchId, delegate.get());
        EXPECT_EQ(20, delegate->scroll_y());
        EXPECT_EQ(0, delegate->scroll_x());
        EXPECT_EQ(0, delegate->scroll_velocity_x());

        // Get a high y velocity, while still staying on the rail
        const int kScrollAmount = 8;
        tes.SendScrollEvents(event_processor(),
            1,
            6,
            10,
            100,
            kTouchId,
            1,
            kScrollAmount,
            delegate.get());
        EXPECT_EQ(0, delegate->scroll_velocity_x());

        delegate->Reset();
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 206),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&release);

        EXPECT_TRUE(delegate->fling());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_EQ(0, delegate->velocity_x());
        EXPECT_GT(delegate->velocity_y(), 0);
    }

    // Check Scroll End Events report non-zero velocities if the user is not on a
    // rail
    TEST_F(GestureRecognizerTest, GestureEventNonRailFling)
    {
        ui::GestureConfiguration::GetInstance()
            ->set_max_touch_move_in_pixels_for_click(0);
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kTouchId = 7;
        gfx::Rect bounds(0, 0, 1000, 1000);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);

        // Move the touch-point such that a non-rail scroll begins, and we're outside
        // the snap channel for the unified GR.
        tes.SendScrollEvent(event_processor(), 50, 50, kTouchId, delegate.get());
        EXPECT_EQ(50, delegate->scroll_y());
        EXPECT_EQ(50, delegate->scroll_x());

        const int kScrollAmount = 8;
        tes.SendScrollEvents(event_processor(),
            1,
            1,
            10,
            100,
            kTouchId,
            1,
            kScrollAmount,
            delegate.get());

        delegate->Reset();
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&release);

        EXPECT_TRUE(delegate->fling());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_GT(delegate->velocity_x(), 0);
        EXPECT_GT(delegate->velocity_y(), 0);
    }

    // Check that appropriate touch events generate long press events
    TEST_F(GestureRecognizerTest, GestureEventLongPress)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 2;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED,
            gfx::Point(101, 201),
            kTouchId,
            ui::EventTimeForNow());
        DispatchEventUsingWindowDispatcher(&press1);
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_TRUE(delegate->begin());
        EXPECT_FALSE(delegate->tap_cancel());

        // We haven't pressed long enough for a long press to occur
        EXPECT_FALSE(delegate->long_press());

        // Wait until the timer runs out
        delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_LONG_PRESS);
        EXPECT_TRUE(delegate->long_press());
        EXPECT_FALSE(delegate->tap_cancel());

        delegate->Reset();
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED,
            gfx::Point(101, 201),
            kTouchId,
            ui::EventTimeForNow());
        DispatchEventUsingWindowDispatcher(&release1);
        EXPECT_FALSE(delegate->long_press());

        // Note the tap cancel isn't dispatched until the release
        EXPECT_TRUE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->tap());
    }

    // Check that scrolling prevents a long press.
    TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledByScroll)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 6;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        EXPECT_TRUE(delegate->tap_down());

        // We haven't pressed long enough for a long press to occur
        EXPECT_FALSE(delegate->long_press());
        EXPECT_FALSE(delegate->tap_cancel());

        // Scroll around, to cancel the long press
        tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());

        // Wait until a long press event would have fired, if it hadn't been
        // cancelled.
        DelayByLongPressTimeout();

        EXPECT_FALSE(delegate->long_press());
        EXPECT_TRUE(delegate->tap_cancel());

        delegate->Reset();
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.LeapForward(10));
        DispatchEventUsingWindowDispatcher(&release1);
        EXPECT_FALSE(delegate->long_press());
        EXPECT_FALSE(delegate->tap_cancel());
    }

    // Check that appropriate touch events generate long tap events
    TEST_F(GestureRecognizerTest, GestureEventLongTap)
    {
        ui::GestureConfiguration::GetInstance()
            ->set_max_touch_down_duration_for_click_in_ms(3);
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 2;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED,
            gfx::Point(101, 201),
            kTouchId,
            ui::EventTimeForNow());
        DispatchEventUsingWindowDispatcher(&press1);
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_TRUE(delegate->begin());
        EXPECT_FALSE(delegate->tap_cancel());

        // We haven't pressed long enough for a long press to occur
        EXPECT_FALSE(delegate->long_press());

        // Wait until the timer runs out
        delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_LONG_PRESS);
        EXPECT_TRUE(delegate->long_press());
        EXPECT_FALSE(delegate->tap_cancel());

        delegate->Reset();
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED,
            gfx::Point(101, 201),
            kTouchId,
            ui::EventTimeForNow());
        DispatchEventUsingWindowDispatcher(&release1);
        EXPECT_FALSE(delegate->long_press());
        EXPECT_TRUE(delegate->long_tap());

        // Note the tap cancel isn't dispatched until the release
        EXPECT_TRUE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->tap());
    }

    // Check that second tap cancels a long press
    TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 300;
        const int kWindowHeight = 400;
        const int kTouchId1 = 8;
        const int kTouchId2 = 2;
        gfx::Rect bounds(5, 5, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_TRUE(delegate->begin());

        // We haven't pressed long enough for a long press to occur
        EXPECT_FALSE(delegate->long_press());

        // Second tap, to cancel the long press
        delegate->Reset();
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);
        EXPECT_FALSE(delegate->tap_down()); // no touch down for second tap.
        EXPECT_TRUE(delegate->tap_cancel());
        EXPECT_TRUE(delegate->begin());

        // Wait until the timer runs out
        DelayByLongPressTimeout();

        // No long press occurred
        EXPECT_FALSE(delegate->long_press());

        delegate->Reset();
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&release1);
        EXPECT_FALSE(delegate->long_press());
        EXPECT_TRUE(delegate->two_finger_tap());
        EXPECT_FALSE(delegate->tap_cancel());
    }

    // Check that horizontal scroll gestures cause scrolls on horizontal rails.
    // Also tests that horizontal rails can be broken.
    TEST_F(GestureRecognizerTest, GestureEventHorizontalRailScroll)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kTouchId = 7;
        gfx::Rect bounds(0, 0, 1000, 1000);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);

        // Get rid of touch slop.
        ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(5, 0),
            kTouchId, tes.Now());

        DispatchEventUsingWindowDispatcher(&move);
        delegate->Reset();

        // Move the touch-point horizontally enough that it is considered a
        // horizontal scroll.
        tes.SendScrollEvent(event_processor(), 25, 0, kTouchId, delegate.get());
        EXPECT_EQ(0, delegate->scroll_y());
        EXPECT_EQ(20, delegate->scroll_x());

        tes.SendScrollEvent(event_processor(), 30, 6, kTouchId, delegate.get());
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_EQ(5, delegate->scroll_x());
        // y shouldn't change, as we're on a horizontal rail.
        EXPECT_EQ(0, delegate->scroll_y());

        // Send enough information that a velocity can be calculated for the gesture,
        // and we can break the rail
        const int kScrollAmount = 8;
        tes.SendScrollEvents(event_processor(),
            1,
            1,
            6,
            100,
            kTouchId,
            1,
            kScrollAmount,
            delegate.get());

        tes.SendScrollEvent(event_processor(), 5, 0, kTouchId, delegate.get());
        tes.SendScrollEvent(event_processor(), 10, 5, kTouchId, delegate.get());

        // The rail should be broken
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_EQ(5, delegate->scroll_x());
        EXPECT_EQ(5, delegate->scroll_y());
    }

    // Check that vertical scroll gestures cause scrolls on vertical rails.
    // Also tests that vertical rails can be broken.
    TEST_F(GestureRecognizerTest, GestureEventVerticalRailScroll)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kTouchId = 7;
        gfx::Rect bounds(0, 0, 1000, 1000);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);

        // Get rid of touch slop.
        ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(0, 5),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&move);
        delegate->Reset();

        // Move the touch-point vertically enough that it is considered a
        // vertical scroll.
        tes.SendScrollEvent(event_processor(), 0, 25, kTouchId, delegate.get());
        EXPECT_EQ(0, delegate->scroll_x());
        EXPECT_EQ(20, delegate->scroll_y());

        tes.SendScrollEvent(event_processor(), 6, 30, kTouchId, delegate.get());
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_EQ(5, delegate->scroll_y());
        // x shouldn't change, as we're on a vertical rail.
        EXPECT_EQ(0, delegate->scroll_x());
        EXPECT_EQ(0, delegate->scroll_velocity_x());

        // Send enough information that a velocity can be calculated for the gesture,
        // and we can break the rail
        const int kScrollAmount = 8;
        tes.SendScrollEvents(event_processor(),
            1,
            6,
            100,
            1,
            kTouchId,
            1,
            kScrollAmount,
            delegate.get());

        tes.SendScrollEvent(event_processor(), 0, 5, kTouchId, delegate.get());
        tes.SendScrollEvent(event_processor(), 5, 10, kTouchId, delegate.get());

        // The rail should be broken
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_EQ(5, delegate->scroll_x());
        EXPECT_EQ(5, delegate->scroll_y());
    }

    TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll)
    {
        // We'll start by moving the touch point by (5, 5). We want all of that
        // distance to be consumed by the slop, so we set the slop radius to
        // sqrt(5 * 5 + 5 * 5).
        ui::GestureConfiguration::GetInstance()
            ->set_max_touch_move_in_pixels_for_click(sqrt(5.f * 5 + 5 * 5));

        // First, tap. Then, do a scroll using the same touch-id.
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 3;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_FALSE(delegate->tap());
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());

        // Make sure there is enough delay before the touch is released so that it is
        // recognized as a tap.
        delegate->Reset();
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release);
        EXPECT_TRUE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());

        // Now, do a scroll gesture. Delay it sufficiently so that it doesn't trigger
        // a double-tap.
        delegate->Reset();
        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.LeapForward(1000));
        DispatchEventUsingWindowDispatcher(&press1);
        EXPECT_FALSE(delegate->tap());
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());

        // Get rid of touch slop.
        ui::TouchEvent move_remove_slop(ui::ET_TOUCH_MOVED, gfx::Point(116, 216),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&move_remove_slop);
        EXPECT_TRUE(delegate->tap_cancel());
        EXPECT_TRUE(delegate->scroll_begin());
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_EQ(15, delegate->scroll_x_hint());
        EXPECT_EQ(15, delegate->scroll_y_hint());

        delegate->Reset();

        // Move the touch-point enough so that it is considered as a scroll. This
        // should generate both SCROLL_BEGIN and SCROLL_UPDATE gestures.
        // The first movement is diagonal, to ensure that we have a free scroll,
        // and not a rail scroll.
        delegate->Reset();
        ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(135, 235),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&move);
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_EQ(19, delegate->scroll_x());
        EXPECT_EQ(19, delegate->scroll_y());

        // Move some more to generate a few more scroll updates.
        delegate->Reset();
        ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(115, 216),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&move1);
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_EQ(-20, delegate->scroll_x());
        EXPECT_EQ(-19, delegate->scroll_y());
        EXPECT_EQ(0, delegate->scroll_x_hint());
        EXPECT_EQ(0, delegate->scroll_y_hint());

        delegate->Reset();
        ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(145, 220),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&move2);
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_EQ(30, delegate->scroll_x());
        EXPECT_EQ(4, delegate->scroll_y());

        // Release the touch. This should end the scroll.
        delegate->Reset();
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&release1);
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_TRUE(delegate->fling());
    }

    TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition)
    {
        scoped_ptr<QueueTouchEventDelegate> queued_delegate(
            new QueueTouchEventDelegate(host()->dispatcher()));
        TimedEvents tes;
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId1 = 6;
        const int kTouchId2 = 4;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> queue(CreateTestWindowWithDelegate(
            queued_delegate.get(), -1234, bounds, root_window()));

        queued_delegate->set_window(queue.get());

        // Touch down on the window. This should not generate any gesture event.
        queued_delegate->Reset();
        ui::TouchEvent press(
            ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_FALSE(queued_delegate->tap());
        EXPECT_FALSE(queued_delegate->tap_down());
        EXPECT_FALSE(queued_delegate->tap_cancel());
        EXPECT_FALSE(queued_delegate->begin());
        EXPECT_FALSE(queued_delegate->scroll_begin());
        EXPECT_FALSE(queued_delegate->scroll_update());
        EXPECT_FALSE(queued_delegate->scroll_end());

        // Introduce some delay before the touch is released so that it is recognized
        // as a tap. However, this still should not create any gesture events.
        queued_delegate->Reset();
        ui::TouchEvent release(
            ui::ET_TOUCH_RELEASED,
            gfx::Point(101, 201),
            kTouchId1,
            press.time_stamp() + base::TimeDelta::FromMilliseconds(50));
        DispatchEventUsingWindowDispatcher(&release);
        EXPECT_FALSE(queued_delegate->tap());
        EXPECT_FALSE(queued_delegate->tap_down());
        EXPECT_FALSE(queued_delegate->tap_cancel());
        EXPECT_FALSE(queued_delegate->begin());
        EXPECT_FALSE(queued_delegate->end());
        EXPECT_FALSE(queued_delegate->scroll_begin());
        EXPECT_FALSE(queued_delegate->scroll_update());
        EXPECT_FALSE(queued_delegate->scroll_end());

        // Create another window, and place a touch-down on it. This should create a
        // tap-down gesture.
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -2345, gfx::Rect(0, 0, 50, 50), root_window()));
        delegate->Reset();
        ui::TouchEvent press2(
            ui::ET_TOUCH_PRESSED, gfx::Point(10, 20), kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);
        EXPECT_FALSE(delegate->tap());
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(queued_delegate->begin());
        EXPECT_FALSE(queued_delegate->end());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());

        ui::TouchEvent release2(
            ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&release2);

        // Process the first queued event.
        queued_delegate->Reset();
        queued_delegate->ReceivedAck();
        EXPECT_FALSE(queued_delegate->tap());
        EXPECT_TRUE(queued_delegate->tap_down());
        EXPECT_TRUE(queued_delegate->begin());
        EXPECT_FALSE(queued_delegate->tap_cancel());
        EXPECT_FALSE(queued_delegate->end());
        EXPECT_FALSE(queued_delegate->scroll_begin());
        EXPECT_FALSE(queued_delegate->scroll_update());
        EXPECT_FALSE(queued_delegate->scroll_end());

        // Now, process the second queued event.
        queued_delegate->Reset();
        queued_delegate->ReceivedAck();
        EXPECT_TRUE(queued_delegate->tap());
        EXPECT_FALSE(queued_delegate->tap_down());
        EXPECT_FALSE(queued_delegate->tap_cancel());
        EXPECT_FALSE(queued_delegate->begin());
        EXPECT_TRUE(queued_delegate->end());
        EXPECT_FALSE(queued_delegate->scroll_begin());
        EXPECT_FALSE(queued_delegate->scroll_update());
        EXPECT_FALSE(queued_delegate->scroll_end());

        // Start all over. Press on the first window, then press again on the second
        // window. The second press should still go to the first window.
        queued_delegate->Reset();
        ui::TouchEvent press3(
            ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press3);
        EXPECT_FALSE(queued_delegate->tap());
        EXPECT_FALSE(queued_delegate->tap_down());
        EXPECT_FALSE(queued_delegate->tap_cancel());
        EXPECT_FALSE(queued_delegate->begin());
        EXPECT_FALSE(queued_delegate->end());
        EXPECT_FALSE(queued_delegate->begin());
        EXPECT_FALSE(queued_delegate->end());
        EXPECT_FALSE(queued_delegate->scroll_begin());
        EXPECT_FALSE(queued_delegate->scroll_update());
        EXPECT_FALSE(queued_delegate->scroll_end());

        queued_delegate->Reset();
        delegate->Reset();
        ui::TouchEvent press4(
            ui::ET_TOUCH_PRESSED, gfx::Point(103, 203), kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press4);
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->begin());
        EXPECT_FALSE(delegate->end());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_FALSE(queued_delegate->tap());
        EXPECT_FALSE(queued_delegate->tap_down());
        EXPECT_FALSE(queued_delegate->tap_cancel());
        EXPECT_FALSE(queued_delegate->begin());
        EXPECT_FALSE(queued_delegate->end());
        EXPECT_FALSE(queued_delegate->scroll_begin());
        EXPECT_FALSE(queued_delegate->scroll_update());
        EXPECT_FALSE(queued_delegate->scroll_end());

        // Move the second touch-point enough so that it is considered a pinch. This
        // should generate both SCROLL_BEGIN and PINCH_BEGIN gestures.
        queued_delegate->Reset();
        delegate->Reset();
        ui::TouchEvent move(ui::ET_TOUCH_MOVED,
            gfx::Point(203 + ui::GestureConfiguration::GetInstance()->max_touch_move_in_pixels_for_click(),
                303),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&move);
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->begin());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_FALSE(queued_delegate->tap());
        EXPECT_FALSE(queued_delegate->tap_down());
        EXPECT_FALSE(queued_delegate->tap_cancel());
        EXPECT_FALSE(queued_delegate->begin());
        EXPECT_FALSE(queued_delegate->scroll_begin());
        EXPECT_FALSE(queued_delegate->scroll_update());
        EXPECT_FALSE(queued_delegate->scroll_end());

        queued_delegate->Reset();
        queued_delegate->ReceivedAck();
        EXPECT_FALSE(queued_delegate->tap());
        EXPECT_TRUE(queued_delegate->tap_down());
        EXPECT_TRUE(queued_delegate->begin());
        EXPECT_FALSE(queued_delegate->tap_cancel());
        EXPECT_FALSE(queued_delegate->end());
        EXPECT_FALSE(queued_delegate->scroll_begin());
        EXPECT_FALSE(queued_delegate->scroll_update());
        EXPECT_FALSE(queued_delegate->scroll_end());

        queued_delegate->Reset();
        queued_delegate->ReceivedAck();
        EXPECT_FALSE(queued_delegate->tap());
        EXPECT_FALSE(queued_delegate->tap_down()); // no touch down for second tap.
        EXPECT_TRUE(queued_delegate->tap_cancel());
        EXPECT_TRUE(queued_delegate->begin());
        EXPECT_FALSE(queued_delegate->end());
        EXPECT_FALSE(queued_delegate->scroll_begin());
        EXPECT_FALSE(queued_delegate->scroll_update());
        EXPECT_FALSE(queued_delegate->scroll_end());
        EXPECT_FALSE(queued_delegate->pinch_begin());
        EXPECT_FALSE(queued_delegate->pinch_update());
        EXPECT_FALSE(queued_delegate->pinch_end());

        queued_delegate->Reset();
        queued_delegate->ReceivedAck();
        EXPECT_FALSE(queued_delegate->tap());
        EXPECT_FALSE(queued_delegate->tap_down());
        EXPECT_FALSE(queued_delegate->tap_cancel());
        EXPECT_FALSE(queued_delegate->begin());
        EXPECT_FALSE(queued_delegate->end());
        EXPECT_TRUE(queued_delegate->scroll_begin());

        EXPECT_TRUE(queued_delegate->scroll_update());
        EXPECT_FALSE(queued_delegate->scroll_end());
        EXPECT_TRUE(queued_delegate->pinch_begin());
        EXPECT_FALSE(queued_delegate->pinch_update());
        EXPECT_FALSE(queued_delegate->pinch_end());
    }

    // Check that appropriate touch events generate pinch gesture events.
    TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 300;
        const int kWindowHeight = 400;
        const int kTouchId1 = 5;
        const int kTouchId2 = 3;
        gfx::Rect bounds(5, 5, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_GESTURE_BEGIN,
            ui::ET_GESTURE_TAP_DOWN);

        // Move the touch-point enough so that it is considered as a scroll. This
        // should generate both SCROLL_BEGIN and SCROLL_UPDATE gestures.
        delegate->Reset();
        ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(130, 301),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move);
        EXPECT_3_EVENTS(delegate->events(),
            ui::ET_GESTURE_TAP_CANCEL,
            ui::ET_GESTURE_SCROLL_BEGIN,
            ui::ET_GESTURE_SCROLL_UPDATE);

        // Press the second finger. It should cause pinch-begin. Note that we will not
        // transition to two finger tap here because the touch points are far enough.
        delegate->Reset();
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);
        EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_BEGIN);
        EXPECT_EQ(gfx::Rect(10, 10, 120, 291).ToString(),
            delegate->bounding_box().ToString());

        // Move the first finger.
        delegate->Reset();
        ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(95, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move3);
        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_GESTURE_SCROLL_UPDATE,
            ui::ET_GESTURE_PINCH_BEGIN);
        EXPECT_EQ(gfx::Rect(10, 10, 85, 191).ToString(),
            delegate->bounding_box().ToString());

        // Now move the second finger.
        delegate->Reset();
        ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(55, 15),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&move4);
        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_GESTURE_SCROLL_UPDATE,
            ui::ET_GESTURE_PINCH_UPDATE);
        EXPECT_EQ(gfx::Rect(55, 15, 40, 186).ToString(),
            delegate->bounding_box().ToString());

        // Release the first finger. This should end pinch.
        delegate->Reset();
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&release);
        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_GESTURE_PINCH_END,
            ui::ET_GESTURE_END);
        EXPECT_EQ(gfx::Rect(55, 15, 46, 186).ToString(),
            delegate->bounding_box().ToString());

        // Move the second finger. This should still generate a scroll.
        delegate->Reset();
        ui::TouchEvent move5(ui::ET_TOUCH_MOVED, gfx::Point(25, 10),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&move5);
        EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
        EXPECT_TRUE(delegate->bounding_box().IsEmpty());
    }

    TEST_F(GestureRecognizerTest, GestureEventPinchFromScrollFromPinch)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 300;
        const int kWindowHeight = 400;
        const int kTouchId1 = 5;
        const int kTouchId2 = 3;
        gfx::Rect bounds(5, 5, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 301),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        delegate->Reset();
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);
        EXPECT_FALSE(delegate->pinch_begin());

        // Touch move triggers pinch begin.
        tes.SendScrollEvent(event_processor(), 130, 230, kTouchId1, delegate.get());
        EXPECT_TRUE(delegate->pinch_begin());
        EXPECT_FALSE(delegate->pinch_update());

        // Touch move triggers pinch update.
        tes.SendScrollEvent(event_processor(), 160, 200, kTouchId1, delegate.get());
        EXPECT_FALSE(delegate->pinch_begin());
        EXPECT_TRUE(delegate->pinch_update());

        // Pinch has started, now release the second finger
        delegate->Reset();
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&release);
        EXPECT_TRUE(delegate->pinch_end());

        tes.SendScrollEvent(event_processor(), 130, 230, kTouchId2, delegate.get());
        EXPECT_TRUE(delegate->scroll_update());

        // Pinch again
        delegate->Reset();
        ui::TouchEvent press3(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press3);
        // Now the touch points are close. So we will go into two finger tap.
        // Move the touch-point enough to break two-finger-tap and enter pinch.
        ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(101, 50),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move2);
        EXPECT_TRUE(delegate->pinch_begin());

        tes.SendScrollEvent(event_processor(), 350, 350, kTouchId1, delegate.get());
        EXPECT_TRUE(delegate->pinch_update());
    }

    TEST_F(GestureRecognizerTest, GestureEventPinchFromTap)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 300;
        const int kWindowHeight = 400;
        const int kTouchId1 = 3;
        const int kTouchId2 = 5;
        gfx::Rect bounds(5, 5, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 301),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_GESTURE_BEGIN,
            ui::ET_GESTURE_TAP_DOWN);
        EXPECT_TRUE(delegate->bounding_box().IsEmpty());

        // Press the second finger far enough to break two finger tap.
        delegate->Reset();
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);
        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_GESTURE_TAP_CANCEL,
            ui::ET_GESTURE_BEGIN);
        EXPECT_EQ(gfx::Rect(10, 10, 91, 291).ToString(),
            delegate->bounding_box().ToString());

        // Move the first finger.
        delegate->Reset();
        ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(65, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move3);
        EXPECT_3_EVENTS(delegate->events(),
            ui::ET_GESTURE_SCROLL_BEGIN,
            ui::ET_GESTURE_SCROLL_UPDATE,
            ui::ET_GESTURE_PINCH_BEGIN);
        EXPECT_EQ(gfx::Rect(10, 10, 55, 191).ToString(),
            delegate->bounding_box().ToString());

        // Now move the second finger.
        delegate->Reset();
        ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(55, 15),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&move4);
        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_GESTURE_SCROLL_UPDATE,
            ui::ET_GESTURE_PINCH_UPDATE);
        EXPECT_EQ(gfx::Rect(55, 15, 10, 186).ToString(),
            delegate->bounding_box().ToString());

        // Release the first finger. This should end pinch.
        delegate->Reset();
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId1, tes.LeapForward(10));
        DispatchEventUsingWindowDispatcher(&release);
        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_GESTURE_PINCH_END,
            ui::ET_GESTURE_END);
        EXPECT_EQ(gfx::Rect(55, 15, 46, 186).ToString(),
            delegate->bounding_box().ToString());

        // Move the second finger. This should still generate a scroll.
        delegate->Reset();
        ui::TouchEvent move5(ui::ET_TOUCH_MOVED, gfx::Point(25, 10),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&move5);
        EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
        EXPECT_TRUE(delegate->bounding_box().IsEmpty());
    }

    TEST_F(GestureRecognizerTest, GestureEventIgnoresDisconnectedEvents)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;

        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            6, tes.Now());
        DispatchEventUsingWindowDispatcher(&release1);
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
    }

    // Check that a touch is locked to the window of the closest current touch
    // within max_separation_for_gesture_touches_in_pixels
    TEST_F(GestureRecognizerTest, GestureEventTouchLockSelectsCorrectWindow)
    {
        ui::GestureRecognizer* gesture_recognizer = new ui::GestureRecognizerImpl();
        TimedEvents tes;
        ScopedGestureRecognizerSetter gr_setter(gesture_recognizer);

        ui::GestureConsumer* target;
        const int kNumWindows = 4;

        scoped_ptr<GestureEventConsumeDelegate*[]> delegates(
            new GestureEventConsumeDelegate*[kNumWindows]);

        ui::GestureConfiguration::GetInstance()
            ->set_max_separation_for_gesture_touches_in_pixels(499);

        scoped_ptr<gfx::Rect[]> window_bounds(new gfx::Rect[kNumWindows]);
        window_bounds[0] = gfx::Rect(0, 0, 1, 1);
        window_bounds[1] = gfx::Rect(500, 0, 1, 1);
        window_bounds[2] = gfx::Rect(0, 500, 1, 1);
        window_bounds[3] = gfx::Rect(500, 500, 1, 1);

        scoped_ptr<aura::Window*[]> windows(new aura::Window*[kNumWindows]);

        // Instantiate windows with |window_bounds| and touch each window at
        // its origin.
        for (int i = 0; i < kNumWindows; ++i) {
            delegates[i] = new GestureEventConsumeDelegate();
            windows[i] = CreateTestWindowWithDelegate(
                delegates[i], i, window_bounds[i], root_window());
            windows[i]->set_id(i);
            ui::TouchEvent press(ui::ET_TOUCH_PRESSED, window_bounds[i].origin(),
                i, tes.Now());
            DispatchEventUsingWindowDispatcher(&press);
        }

        // Touches should now be associated with the closest touch within
        // ui::GestureConfiguration::max_separation_for_gesture_touches_in_pixels
        target = gesture_recognizer->GetTargetForLocation(gfx::PointF(11.f, 11.f), -1);
        EXPECT_EQ("0", WindowIDAsString(target));
        target = gesture_recognizer->GetTargetForLocation(gfx::PointF(511.f, 11.f), -1);
        EXPECT_EQ("1", WindowIDAsString(target));
        target = gesture_recognizer->GetTargetForLocation(gfx::PointF(11.f, 511.f), -1);
        EXPECT_EQ("2", WindowIDAsString(target));
        target = gesture_recognizer->GetTargetForLocation(gfx::PointF(511.f, 511.f), -1);
        EXPECT_EQ("3", WindowIDAsString(target));

        // Add a touch in the middle associated with windows[2]
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 500),
            kNumWindows, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(250, 250),
            kNumWindows, tes.Now());
        DispatchEventUsingWindowDispatcher(&move);

        target = gesture_recognizer->GetTargetForLocation(gfx::PointF(250.f, 250.f), -1);
        EXPECT_EQ("2", WindowIDAsString(target));

        // Make sure that ties are broken by distance to a current touch
        // Closer to the point in the bottom right.
        target = gesture_recognizer->GetTargetForLocation(gfx::PointF(380.f, 380.f), -1);
        EXPECT_EQ("3", WindowIDAsString(target));

        // This touch is closer to the point in the middle
        target = gesture_recognizer->GetTargetForLocation(gfx::PointF(300.f, 300.f), -1);
        EXPECT_EQ("2", WindowIDAsString(target));

        // A touch too far from other touches won't be locked to anything
        target = gesture_recognizer->GetTargetForLocation(gfx::PointF(1000.f, 1000.f), -1);
        EXPECT_TRUE(target == NULL);

        // Move a touch associated with windows[2] to 1000, 1000
        ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(1000, 1000),
            kNumWindows, tes.Now());
        DispatchEventUsingWindowDispatcher(&move2);

        target = gesture_recognizer->GetTargetForLocation(gfx::PointF(1000.f, 1000.f), -1);
        EXPECT_EQ("2", WindowIDAsString(target));

        for (int i = 0; i < kNumWindows; ++i) {
            // Delete windows before deleting delegates.
            delete windows[i];
            delete delegates[i];
        }
    }

    // Check that a touch's target will not be effected by a touch on a different
    // screen.
    TEST_F(GestureRecognizerTest, GestureEventTouchLockIgnoresOtherScreens)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        gfx::Rect bounds(0, 0, 10, 10);
        scoped_ptr<aura::Window> window(
            CreateTestWindowWithDelegate(delegate.get(), 0, bounds, root_window()));

        const int kTouchId1 = 8;
        const int kTouchId2 = 2;
        TimedEvents tes;

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(5, 5),
            kTouchId1, tes.Now());
        ui::EventTestApi test_press1(&press1);
        test_press1.set_source_device_id(1);
        DispatchEventUsingWindowDispatcher(&press1);

        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(20, 20),
            kTouchId2, tes.Now());
        ui::EventTestApi test_press2(&press2);
        test_press2.set_source_device_id(2);
        DispatchEventUsingWindowDispatcher(&press2);

        // The second press should not have been locked to the same target as the
        // first, as they occured on different displays.
        EXPECT_NE(
            ui::GestureRecognizer::Get()->GetTouchLockedTarget(press1),
            ui::GestureRecognizer::Get()->GetTouchLockedTarget(press2));
    }

    // Check that touch events outside the root window are still handled
    // by the root window's gesture sequence.
    TEST_F(GestureRecognizerTest, GestureEventOutsideRootWindowTap)
    {
        TimedEvents tes;
        scoped_ptr<aura::Window> window(CreateTestWindowWithBounds(
            gfx::Rect(-100, -100, 2000, 2000), root_window()));

        gfx::Point pos1(-10, -10);
        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, pos1, 0, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);

        gfx::Point pos2(1000, 1000);
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, pos2, 1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);

        // As these presses were outside the root window, they should be
        // associated with the root window.
        EXPECT_EQ(root_window(),
            static_cast<aura::Window*>(
                ui::GestureRecognizer::Get()->GetTouchLockedTarget(press1)));
        EXPECT_EQ(root_window(),
            static_cast<aura::Window*>(
                ui::GestureRecognizer::Get()->GetTouchLockedTarget(press2)));
    }

    TEST_F(GestureRecognizerTest, NoTapWithPreventDefaultedRelease)
    {
        scoped_ptr<QueueTouchEventDelegate> delegate(
            new QueueTouchEventDelegate(host()->dispatcher()));
        TimedEvents tes;
        const int kTouchId = 2;
        gfx::Rect bounds(100, 200, 100, 100);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        delegate->set_window(window.get());

        delegate->Reset();
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release);

        delegate->Reset();
        delegate->ReceivedAck();
        EXPECT_TRUE(delegate->tap_down());
        delegate->Reset();
        delegate->ReceivedAckPreventDefaulted();
        EXPECT_FALSE(delegate->tap());
        EXPECT_TRUE(delegate->tap_cancel());
    }

    TEST_F(GestureRecognizerTest, PinchScrollWithPreventDefaultedRelease)
    {
        scoped_ptr<QueueTouchEventDelegate> delegate(
            new QueueTouchEventDelegate(host()->dispatcher()));
        TimedEvents tes;
        const int kTouchId1 = 7;
        const int kTouchId2 = 5;
        gfx::Rect bounds(10, 20, 100, 100);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        delegate->set_window(window.get());

        {
            delegate->Reset();
            ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(15, 25), kTouchId1,
                tes.Now());
            ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(20, 95), kTouchId1,
                tes.LeapForward(200));
            ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(15, 25), kTouchId1,
                tes.LeapForward(50));
            DispatchEventUsingWindowDispatcher(&press);
            DispatchEventUsingWindowDispatcher(&move);
            DispatchEventUsingWindowDispatcher(&release);
            delegate->Reset();

            // Ack the press event.
            delegate->ReceivedAck();
            EXPECT_2_EVENTS(
                delegate->events(), ui::ET_GESTURE_BEGIN, ui::ET_GESTURE_TAP_DOWN);
            delegate->Reset();

            // Ack the move event.
            delegate->ReceivedAck();
            EXPECT_3_EVENTS(delegate->events(),
                ui::ET_GESTURE_TAP_CANCEL,
                ui::ET_GESTURE_SCROLL_BEGIN,
                ui::ET_GESTURE_SCROLL_UPDATE);
            delegate->Reset();

            // Ack the release event. Although the release event has been processed, it
            // should still generate a scroll-end event.
            delegate->ReceivedAckPreventDefaulted();
            EXPECT_2_EVENTS(
                delegate->events(), ui::ET_GESTURE_SCROLL_END, ui::ET_GESTURE_END);
        }

        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(15, 25), kTouchId1,
            tes.Now());
        ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(20, 95), kTouchId1,
            tes.LeapForward(200));
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(15, 25), kTouchId1,
            tes.LeapForward(50));
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(55, 25), kTouchId2,
            tes.Now());
        ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(145, 85), kTouchId2,
            tes.LeapForward(1000));
        ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(145, 85), kTouchId2,
            tes.LeapForward(14));

        // Do a pinch.
        DispatchEventUsingWindowDispatcher(&press);
        DispatchEventUsingWindowDispatcher(&move);
        DispatchEventUsingWindowDispatcher(&press2);
        DispatchEventUsingWindowDispatcher(&move2);
        DispatchEventUsingWindowDispatcher(&release);
        DispatchEventUsingWindowDispatcher(&release2);

        // Ack the press and move events.
        delegate->Reset();
        delegate->ReceivedAck();
        EXPECT_2_EVENTS(
            delegate->events(), ui::ET_GESTURE_BEGIN, ui::ET_GESTURE_TAP_DOWN);

        delegate->Reset();
        delegate->ReceivedAck();
        EXPECT_3_EVENTS(delegate->events(),
            ui::ET_GESTURE_TAP_CANCEL,
            ui::ET_GESTURE_SCROLL_BEGIN,
            ui::ET_GESTURE_SCROLL_UPDATE);

        delegate->Reset();
        delegate->ReceivedAck();
        EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_BEGIN);

        delegate->Reset();
        delegate->ReceivedAck();
        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_GESTURE_SCROLL_UPDATE,
            ui::ET_GESTURE_PINCH_BEGIN);

        // Ack the first release. Although the release is processed, it should still
        // generate a pinch-end event.
        delegate->Reset();
        delegate->ReceivedAckPreventDefaulted();
        EXPECT_2_EVENTS(
            delegate->events(), ui::ET_GESTURE_PINCH_END, ui::ET_GESTURE_END);

        delegate->Reset();
        delegate->ReceivedAckPreventDefaulted();
        EXPECT_2_EVENTS(
            delegate->events(), ui::ET_GESTURE_SCROLL_END, ui::ET_GESTURE_END);
    }

    TEST_F(GestureRecognizerTest, GestureEndLocation)
    {
        GestureEventConsumeDelegate delegate;
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            &delegate, -1234, gfx::Rect(10, 10, 300, 300), root_window()));
        ui::test::EventGenerator generator(root_window(), window.get());
        const gfx::Point begin(20, 20);
        const gfx::Point end(150, 150);
        const gfx::Vector2d window_offset = window->bounds().origin().OffsetFromOrigin();
        generator.GestureScrollSequence(begin, end,
            base::TimeDelta::FromMilliseconds(20),
            10);
        EXPECT_EQ((begin - window_offset).ToString(),
            delegate.scroll_begin_position().ToString());
        EXPECT_EQ((end - window_offset).ToString(),
            delegate.gesture_end_location().ToString());
    }

    TEST_F(GestureRecognizerTest, CaptureSendsGestureEnd)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, gfx::Rect(10, 10, 300, 300), root_window()));
        ui::test::EventGenerator generator(root_window());

        generator.MoveMouseRelativeTo(window.get(), gfx::Point(10, 10));
        generator.PressTouch();
        RunAllPendingInMessageLoop();

        EXPECT_TRUE(delegate->tap_down());

        scoped_ptr<aura::Window> capture(CreateTestWindowWithBounds(
            gfx::Rect(10, 10, 200, 200), root_window()));
        capture->SetCapture();
        RunAllPendingInMessageLoop();

        EXPECT_TRUE(delegate->end());
        EXPECT_TRUE(delegate->tap_cancel());
    }

    // Check that previous touch actions that are completely finished (either
    // released or cancelled), do not receive extra synthetic cancels upon change of
    // capture.
    TEST_F(GestureRecognizerTest, CaptureDoesNotCancelFinishedTouches)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        scoped_ptr<TestEventHandler> handler(new TestEventHandler);
        root_window()->AddPreTargetHandler(handler.get());

        // Create a window and set it as the capture window.
        scoped_ptr<aura::Window> window1(CreateTestWindowWithDelegate(delegate.get(),
            -1234, gfx::Rect(10, 10, 300, 300), root_window()));
        window1->SetCapture();

        ui::test::EventGenerator generator(root_window());
        TimedEvents tes;

        // Generate two touch-press events on the window.
        scoped_ptr<ui::TouchEvent> touch0(new ui::TouchEvent(ui::ET_TOUCH_PRESSED,
            gfx::Point(20, 20), 0,
            tes.Now()));
        scoped_ptr<ui::TouchEvent> touch1(new ui::TouchEvent(ui::ET_TOUCH_PRESSED,
            gfx::Point(30, 30), 1,
            tes.Now()));
        generator.Dispatch(touch0.get());
        generator.Dispatch(touch1.get());
        RunAllPendingInMessageLoop();
        EXPECT_EQ(2, handler->touch_pressed_count());

        // Advance time.
        tes.LeapForward(1000);

        // End the two touches, one by a touch-release and one by a touch-cancel; to
        // cover both cases.
        touch0.reset(new ui::TouchEvent(ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), 0,
            tes.Now()));
        touch1.reset(new ui::TouchEvent(ui::ET_TOUCH_CANCELLED, gfx::Point(30, 30), 1,
            tes.Now()));
        generator.Dispatch(touch0.get());
        generator.Dispatch(touch1.get());
        RunAllPendingInMessageLoop();
        EXPECT_EQ(1, handler->touch_released_count());
        EXPECT_EQ(1, handler->touch_cancelled_count());

        // Create a new window and set it as the new capture window.
        scoped_ptr<aura::Window> window2(CreateTestWindowWithBounds(
            gfx::Rect(100, 100, 300, 300), root_window()));
        window2->SetCapture();
        RunAllPendingInMessageLoop();
        // Check that setting capture does not generate any synthetic touch-cancels
        // for the two previously finished touch actions.
        EXPECT_EQ(1, handler->touch_cancelled_count());

        root_window()->RemovePreTargetHandler(handler.get());
    }

    // Tests that a press with the same touch id as an existing touch is ignored.
    TEST_F(GestureRecognizerTest, PressDoesNotCrash)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;

        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, gfx::Rect(10, 10, 300, 300), root_window()));

        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(45, 45), 7, tes.Now());
        SetTouchRadius(&press, 40, 0);
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_EQ(gfx::Rect(5, 5, 80, 80).ToString(),
            delegate->bounding_box().ToString());
        delegate->Reset();

        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(55, 45), 7, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);

        // FIXME(tdresser): this should not generate a tap down; however,
        // there is at least one case where we need to allow a touch press
        // from a currently used touch id. See crbug.com/373125 for details.
        EXPECT_TRUE(delegate->begin());
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_TRUE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->scroll_begin());
    }

    TEST_F(GestureRecognizerTest, TwoFingerTap)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId1 = 2;
        const int kTouchId2 = 3;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        TimedEvents tes;

        delegate->Reset();
        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        EXPECT_2_EVENTS(
            delegate->events(), ui::ET_GESTURE_BEGIN, ui::ET_GESTURE_TAP_DOWN);

        delegate->Reset();
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);
        EXPECT_2_EVENTS(
            delegate->events(), ui::ET_GESTURE_TAP_CANCEL, ui::ET_GESTURE_BEGIN);

        // Little bit of touch move should not affect our state.
        delegate->Reset();
        ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(102, 202),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move1);
        ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(131, 202),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&move2);
        EXPECT_3_EVENTS(delegate->events(), ui::ET_GESTURE_SCROLL_BEGIN,
            ui::ET_GESTURE_SCROLL_UPDATE, ui::ET_GESTURE_SCROLL_UPDATE);

        // Make sure there is enough delay before the touch is released so that it is
        // recognized as a tap.
        delegate->Reset();
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId1, tes.LeapForward(50));

        DispatchEventUsingWindowDispatcher(&release1);
        EXPECT_2_EVENTS(
            delegate->events(), ui::ET_GESTURE_TWO_FINGER_TAP, ui::ET_GESTURE_END);

        // Lift second finger.
        // Make sure there is enough delay before the touch is released so that it is
        // recognized as a tap.
        delegate->Reset();
        ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(130, 201),
            kTouchId2, tes.LeapForward(50));

        DispatchEventUsingWindowDispatcher(&release2);
        EXPECT_2_EVENTS(
            delegate->events(), ui::ET_GESTURE_SCROLL_END, ui::ET_GESTURE_END);
    }

    TEST_F(GestureRecognizerTest, TwoFingerTapExpired)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId1 = 2;
        const int kTouchId2 = 3;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        TimedEvents tes;

        delegate->Reset();
        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);

        delegate->Reset();
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);

        // Send release event after sufficient delay so that two finger time expires.
        delegate->Reset();
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId1, tes.LeapForward(1000));

        DispatchEventUsingWindowDispatcher(&release1);
        EXPECT_FALSE(delegate->two_finger_tap());

        // Lift second finger.
        // Make sure there is enough delay before the touch is released so that it is
        // recognized as a tap.
        delegate->Reset();
        ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(130, 201),
            kTouchId2, tes.LeapForward(50));

        DispatchEventUsingWindowDispatcher(&release2);
        EXPECT_FALSE(delegate->two_finger_tap());
    }

    TEST_F(GestureRecognizerTest, TwoFingerTapChangesToPinch)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId1 = 2;
        const int kTouchId2 = 3;
        TimedEvents tes;

        // Test moving first finger
        {
            gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
            scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
                delegate.get(), -1234, bounds, root_window()));

            delegate->Reset();
            ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
                kTouchId1, tes.Now());
            DispatchEventUsingWindowDispatcher(&press1);

            delegate->Reset();
            ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
                kTouchId2, tes.Now());
            DispatchEventUsingWindowDispatcher(&press2);

            tes.SendScrollEvent(event_processor(), 230, 330, kTouchId1, delegate.get());
            EXPECT_FALSE(delegate->two_finger_tap());
            EXPECT_TRUE(delegate->pinch_begin());

            // Make sure there is enough delay before the touch is released so that it
            // is recognized as a tap.
            delegate->Reset();
            ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
                kTouchId2, tes.LeapForward(50));

            DispatchEventUsingWindowDispatcher(&release);
            EXPECT_FALSE(delegate->two_finger_tap());
            EXPECT_TRUE(delegate->pinch_end());
        }

        // Test moving second finger
        {
            gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
            scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
                delegate.get(), -1234, bounds, root_window()));

            delegate->Reset();
            ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
                kTouchId1, tes.Now());
            DispatchEventUsingWindowDispatcher(&press1);

            delegate->Reset();
            ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
                kTouchId2, tes.Now());
            DispatchEventUsingWindowDispatcher(&press2);

            tes.SendScrollEvent(event_processor(), 301, 230, kTouchId2, delegate.get());
            EXPECT_FALSE(delegate->two_finger_tap());
            EXPECT_TRUE(delegate->pinch_begin());

            // Make sure there is enough delay before the touch is released so that it
            // is recognized as a tap.
            delegate->Reset();
            ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
                kTouchId1, tes.LeapForward(50));

            DispatchEventUsingWindowDispatcher(&release);
            EXPECT_FALSE(delegate->two_finger_tap());
            EXPECT_TRUE(delegate->pinch_end());
        }
    }

    TEST_F(GestureRecognizerTest, NoTwoFingerTapWhenFirstFingerHasScrolled)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId1 = 2;
        const int kTouchId2 = 3;
        TimedEvents tes;

        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();
        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        tes.SendScrollEvent(event_processor(), 130, 230, kTouchId1, delegate.get());

        delegate->Reset();
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);

        EXPECT_FALSE(delegate->pinch_begin());

        // Make sure there is enough delay before the touch is released so that it
        // is recognized as a tap.
        delegate->Reset();
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId2, tes.LeapForward(50));

        DispatchEventUsingWindowDispatcher(&release);
        EXPECT_FALSE(delegate->two_finger_tap());
        EXPECT_FALSE(delegate->pinch_end());
    }

    TEST_F(GestureRecognizerTest, MultiFingerSwipe)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;

        gfx::Rect bounds(5, 10, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        const int kSteps = 15;
        const int kTouchPoints = 4;
        gfx::Point points[kTouchPoints] = {
            gfx::Point(10, 30),
            gfx::Point(30, 20),
            gfx::Point(50, 30),
            gfx::Point(80, 50)
        };

        ui::test::EventGenerator generator(root_window(), window.get());

        // The unified gesture recognizer assumes a finger has stopped if it hasn't
        // moved for too long. See ui/events/gesture_detection/velocity_tracker.cc's
        // kAssumePointerStoppedTimeMs.
        for (int count = 2; count <= kTouchPoints; ++count) {
            generator.GestureMultiFingerScroll(
                count, points, 10, kSteps, 0, -11 * kSteps);
            EXPECT_TRUE(delegate->swipe_up());
            delegate->Reset();

            generator.GestureMultiFingerScroll(
                count, points, 10, kSteps, 0, 11 * kSteps);
            EXPECT_TRUE(delegate->swipe_down());
            delegate->Reset();

            generator.GestureMultiFingerScroll(
                count, points, 10, kSteps, -11 * kSteps, 0);
            EXPECT_TRUE(delegate->swipe_left());
            delegate->Reset();

            generator.GestureMultiFingerScroll(
                count, points, 10, kSteps, 11 * kSteps, 0);
            EXPECT_TRUE(delegate->swipe_right());
            delegate->Reset();

            generator.GestureMultiFingerScroll(
                count, points, 10, kSteps, 5 * kSteps, 12 * kSteps);
            EXPECT_FALSE(delegate->swipe_down());
            delegate->Reset();

            generator.GestureMultiFingerScroll(
                count, points, 10, kSteps, 4 * kSteps, 12 * kSteps);
            EXPECT_TRUE(delegate->swipe_down());
            delegate->Reset();

            generator.GestureMultiFingerScroll(
                count, points, 10, kSteps, 3 * kSteps, 12 * kSteps);
            EXPECT_TRUE(delegate->swipe_down());
            delegate->Reset();
        }
    }

    TEST_F(GestureRecognizerTest, TwoFingerTapCancelled)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId1 = 2;
        const int kTouchId2 = 3;
        TimedEvents tes;

        // Test canceling first finger.
        {
            gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
            scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
                delegate.get(), -1234, bounds, root_window()));

            delegate->Reset();
            ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
                kTouchId1, tes.Now());
            DispatchEventUsingWindowDispatcher(&press1);

            delegate->Reset();
            ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
                kTouchId2, tes.Now());
            DispatchEventUsingWindowDispatcher(&press2);

            delegate->Reset();
            ui::TouchEvent cancel(ui::ET_TOUCH_CANCELLED, gfx::Point(130, 201),
                kTouchId1, tes.Now());
            DispatchEventUsingWindowDispatcher(&cancel);
            EXPECT_FALSE(delegate->two_finger_tap());

            // Make sure there is enough delay before the touch is released so that it
            // is recognized as a tap.
            delegate->Reset();
            ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
                kTouchId2, tes.LeapForward(50));

            DispatchEventUsingWindowDispatcher(&release);
            EXPECT_FALSE(delegate->two_finger_tap());
        }

        // Test canceling second finger
        {
            gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
            scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
                delegate.get(), -1234, bounds, root_window()));

            delegate->Reset();
            ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
                kTouchId1, tes.Now());
            DispatchEventUsingWindowDispatcher(&press1);

            delegate->Reset();
            ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
                kTouchId2, tes.Now());
            DispatchEventUsingWindowDispatcher(&press2);

            delegate->Reset();
            ui::TouchEvent cancel(ui::ET_TOUCH_CANCELLED, gfx::Point(130, 201),
                kTouchId2, tes.Now());
            DispatchEventUsingWindowDispatcher(&cancel);
            EXPECT_FALSE(delegate->two_finger_tap());

            // Make sure there is enough delay before the touch is released so that it
            // is recognized as a tap.
            delegate->Reset();
            ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
                kTouchId1, tes.LeapForward(50));

            DispatchEventUsingWindowDispatcher(&release);
            EXPECT_FALSE(delegate->two_finger_tap());
        }
    }

    TEST_F(GestureRecognizerTest, VeryWideTwoFingerTouchDownShouldBeAPinch)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 523;
        const int kWindowHeight = 45;
        const int kTouchId1 = 2;
        const int kTouchId2 = 3;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        TimedEvents tes;

        delegate->Reset();
        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        EXPECT_FALSE(delegate->tap());
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_FALSE(delegate->long_press());
        EXPECT_FALSE(delegate->two_finger_tap());

        delegate->Reset();
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(430, 201),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down()); // no touch down for second tap.
        EXPECT_TRUE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_FALSE(delegate->long_press());
        EXPECT_FALSE(delegate->two_finger_tap());
        EXPECT_FALSE(delegate->pinch_begin());

        delegate->Reset();
        ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(530, 301),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&move2);
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        // Pinch & Scroll only when there is enough movement.
        EXPECT_TRUE(delegate->scroll_begin());
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_FALSE(delegate->long_press());
        EXPECT_FALSE(delegate->two_finger_tap());
        EXPECT_TRUE(delegate->pinch_begin());
    }

    // Verifies if a window is the target of multiple touch-ids and we hide the
    // window everything is cleaned up correctly.
    TEST_F(GestureRecognizerTest, FlushAllOnHide)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        gfx::Rect bounds(0, 0, 200, 200);
        scoped_ptr<aura::Window> window(
            CreateTestWindowWithDelegate(delegate.get(), 0, bounds, root_window()));
        const int kTouchId1 = 8;
        const int kTouchId2 = 2;
        TimedEvents tes;

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(20, 20),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);
        window->Hide();
        EXPECT_EQ(NULL,
            ui::GestureRecognizer::Get()->GetTouchLockedTarget(press1));
        EXPECT_EQ(NULL,
            ui::GestureRecognizer::Get()->GetTouchLockedTarget(press2));
    }

    TEST_F(GestureRecognizerTest, LongPressTimerStopsOnPreventDefaultedTouchMoves)
    {
        scoped_ptr<QueueTouchEventDelegate> delegate(
            new QueueTouchEventDelegate(host()->dispatcher()));
        const int kTouchId = 2;
        gfx::Rect bounds(100, 200, 100, 100);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        delegate->set_window(window.get());
        TimedEvents tes;

        delegate->Reset();
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        // Scroll around, to cancel the long press
        tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());

        delegate->Reset();
        delegate->ReceivedAck();
        EXPECT_TRUE(delegate->tap_down());

        // Wait long enough that long press would have fired if the touchmove hadn't
        // prevented it.
        DelayByLongPressTimeout();

        delegate->Reset();
        delegate->ReceivedAckPreventDefaulted();
        EXPECT_FALSE(delegate->long_press());
    }

    // Same as GestureEventConsumeDelegate, but consumes all the touch-move events.
    class ConsumesTouchMovesDelegate : public GestureEventConsumeDelegate {
    public:
        ConsumesTouchMovesDelegate()
            : consume_touch_move_(true)
        {
        }
        ~ConsumesTouchMovesDelegate() override { }

        void set_consume_touch_move(bool consume) { consume_touch_move_ = consume; }

    private:
        void OnTouchEvent(ui::TouchEvent* touch) override
        {
            if (consume_touch_move_ && touch->type() == ui::ET_TOUCH_MOVED)
                touch->SetHandled();
            else
                GestureEventConsumeDelegate::OnTouchEvent(touch);
        }

        bool consume_touch_move_;

        DISALLOW_COPY_AND_ASSIGN(ConsumesTouchMovesDelegate);
    };

    // Same as GestureEventScroll, but tests that the behavior is the same
    // even if all the touch-move events are consumed.
    TEST_F(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed)
    {
        scoped_ptr<ConsumesTouchMovesDelegate> delegate(
            new ConsumesTouchMovesDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 5;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        TimedEvents tes;

        delegate->Reset();
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_FALSE(delegate->tap());
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_TRUE(delegate->begin());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());

        // Move the touch-point enough so that it would normally be considered a
        // scroll. But since the touch-moves will be consumed, the scroll should not
        // start.
        tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_TRUE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());

        EXPECT_TRUE(delegate->scroll_begin());

        // Release the touch back at the start point. This should end without causing
        // a tap.
        delegate->Reset();
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(130, 230),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release);
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->begin());
        EXPECT_TRUE(delegate->end());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());

        EXPECT_TRUE(delegate->scroll_end());
    }

    // Tests the behavior of 2F scroll when some of the touch-move events are
    // consumed.
    TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed)
    {
        scoped_ptr<ConsumesTouchMovesDelegate> delegate(
            new ConsumesTouchMovesDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 100;
        const int kTouchId1 = 2;
        const int kTouchId2 = 3;
        TimedEvents tes;

        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();
        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        tes.SendScrollEvent(event_processor(), 131, 231, kTouchId1, delegate.get());

        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_GESTURE_TAP_CANCEL,
            ui::ET_GESTURE_SCROLL_BEGIN);

        delegate->Reset();
        // Second finger touches down and moves.
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201),
            kTouchId2, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&press2);
        tes.SendScrollEvent(event_processor(), 161, 231, kTouchId2, delegate.get());
        EXPECT_0_EVENTS(delegate->events());

        delegate->Reset();
        // Move first finger again, no PinchUpdate & ScrollUpdate.
        tes.SendScrollEvent(event_processor(), 161, 261, kTouchId1, delegate.get());
        EXPECT_0_EVENTS(delegate->events());

        // Stops consuming touch-move.
        delegate->set_consume_touch_move(false);

        delegate->Reset();
        // Making a pinch gesture.
        tes.SendScrollEvent(event_processor(), 161, 260, kTouchId1, delegate.get());
        EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);

        delegate->Reset();
        tes.SendScrollEvent(event_processor(), 161, 261, kTouchId2, delegate.get());
        EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);

        delegate->Reset();
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId1, tes.Now());
        ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(130, 201),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&release1);
        DispatchEventUsingWindowDispatcher(&release2);

        EXPECT_3_EVENTS(delegate->events(),
            ui::ET_GESTURE_END,
            ui::ET_SCROLL_FLING_START,
            ui::ET_GESTURE_END);
    }

    // Like as GestureEventTouchMoveConsumed but tests the different behavior
    // depending on whether the events were consumed before or after the scroll
    // started.
    TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed)
    {
        scoped_ptr<ConsumesTouchMovesDelegate> delegate(
            new ConsumesTouchMovesDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 5;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        TimedEvents tes;

        delegate->Reset();
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_FALSE(delegate->tap());
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_TRUE(delegate->begin());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());

        // Move the touch-point enough so that it would normally be considered a
        // scroll. But since the touch-moves will be consumed, the scroll should not
        // start.
        tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_TRUE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());

        // Consuming the first touch move event won't prevent all future scrolling.
        EXPECT_TRUE(delegate->scroll_begin());

        // Now, stop consuming touch-move events, and move the touch-point again.
        delegate->set_consume_touch_move(false);
        tes.SendScrollEvent(event_processor(), 159, 259, kTouchId, delegate.get());
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->begin());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_end());

        // Scroll not prevented by consumed first touch move.
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_EQ(29, delegate->scroll_x());
        EXPECT_EQ(29, delegate->scroll_y());
        EXPECT_EQ(gfx::Point(0, 0).ToString(),
            delegate->scroll_begin_position().ToString());

        // Start consuming touch-move events again.
        delegate->set_consume_touch_move(true);

        // Move some more to generate a few more scroll updates.
        tes.SendScrollEvent(event_processor(), 110, 211, kTouchId, delegate.get());
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->begin());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_EQ(0, delegate->scroll_x());
        EXPECT_EQ(0, delegate->scroll_y());

        tes.SendScrollEvent(event_processor(), 140, 215, kTouchId, delegate.get());
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->begin());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());
        EXPECT_EQ(0, delegate->scroll_x());
        EXPECT_EQ(0, delegate->scroll_y());

        // Release the touch.
        delegate->Reset();
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release);
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->begin());
        EXPECT_TRUE(delegate->end());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->fling());

        EXPECT_TRUE(delegate->scroll_end());
    }

    // Check that appropriate touch events generate double tap gesture events.
    TEST_F(GestureRecognizerTest, GestureEventDoubleTap)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 2;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        TimedEvents tes;

        // First tap (tested in GestureEventTap)
        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(104, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(104, 201),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release1);
        delegate->Reset();

        // Second tap
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(101, 203),
            kTouchId, tes.LeapForward(200));
        DispatchEventUsingWindowDispatcher(&press2);
        ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(102, 206),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release2);

        EXPECT_TRUE(delegate->tap());
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_TRUE(delegate->begin());
        EXPECT_TRUE(delegate->end());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());

        EXPECT_EQ(2, delegate->tap_count());
    }

    // Check that appropriate touch events generate triple tap gesture events.
    TEST_F(GestureRecognizerTest, GestureEventTripleTap)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 2;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        TimedEvents tes;

        // First tap (tested in GestureEventTap)
        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(104, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(104, 201),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release1);

        EXPECT_EQ(1, delegate->tap_count());
        delegate->Reset();

        // Second tap (tested in GestureEventDoubleTap)
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(101, 203),
            kTouchId, tes.LeapForward(200));
        DispatchEventUsingWindowDispatcher(&press2);
        ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(102, 206),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release2);

        EXPECT_EQ(2, delegate->tap_count());
        delegate->Reset();

        // Third tap
        ui::TouchEvent press3(ui::ET_TOUCH_PRESSED, gfx::Point(102, 206),
            kTouchId, tes.LeapForward(200));
        DispatchEventUsingWindowDispatcher(&press3);
        ui::TouchEvent release3(ui::ET_TOUCH_RELEASED, gfx::Point(102, 206),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release3);

        // Third, Fourth and Fifth Taps. Taps after the third should have their
        // |tap_count| wrap around back to 1.
        for (int i = 3; i < 5; ++i) {
            ui::TouchEvent press3(ui::ET_TOUCH_PRESSED,
                gfx::Point(102, 206),
                kTouchId,
                tes.LeapForward(200));
            DispatchEventUsingWindowDispatcher(&press3);
            ui::TouchEvent release3(ui::ET_TOUCH_RELEASED,
                gfx::Point(102, 206),
                kTouchId,
                tes.LeapForward(50));
            DispatchEventUsingWindowDispatcher(&release3);

            EXPECT_TRUE(delegate->tap());
            EXPECT_TRUE(delegate->tap_down());
            EXPECT_FALSE(delegate->tap_cancel());
            EXPECT_TRUE(delegate->begin());
            EXPECT_TRUE(delegate->end());
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());
            EXPECT_EQ(1 + (i % 3), delegate->tap_count());
        }
    }

    // Check that we don't get a double tap when the two taps are far apart.
    TEST_F(GestureRecognizerTest, TwoTapsFarApart)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 2;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        TimedEvents tes;

        // First tap (tested in GestureEventTap)
        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release1);
        delegate->Reset();

        // Second tap, close in time but far in distance
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(201, 201),
            kTouchId, tes.LeapForward(200));
        DispatchEventUsingWindowDispatcher(&press2);
        ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(201, 201),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release2);

        EXPECT_TRUE(delegate->tap());
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_TRUE(delegate->begin());
        EXPECT_TRUE(delegate->end());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());

        EXPECT_EQ(1, delegate->tap_count());
    }

    // Check that we don't get a double tap when the two taps have a long enough
    // delay in between.
    TEST_F(GestureRecognizerTest, TwoTapsWithDelayBetween)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 2;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        TimedEvents tes;

        // First tap (tested in GestureEventTap)
        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release1);
        delegate->Reset();

        // Second tap, close in distance but after some delay
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.LeapForward(2000));
        DispatchEventUsingWindowDispatcher(&press2);
        ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release2);

        EXPECT_TRUE(delegate->tap());
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_TRUE(delegate->begin());
        EXPECT_TRUE(delegate->end());
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());

        EXPECT_EQ(1, delegate->tap_count());
    }

    // Checks that if the bounding-box of a gesture changes because of change in
    // radius of a touch-point, and not because of change in position, then there
    // are not gesture events from that.
    TEST_F(GestureRecognizerTest, BoundingBoxRadiusChange)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 234;
        const int kWindowHeight = 345;
        const int kTouchId = 5, kTouchId2 = 7;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        TimedEvents tes;

        ui::TouchEvent press1(
            ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        EXPECT_TRUE(delegate->bounding_box().IsEmpty());

        delegate->Reset();

        ui::TouchEvent press2(
            ui::ET_TOUCH_PRESSED, gfx::Point(201, 201), kTouchId2,
            tes.LeapForward(400));
        SetTouchRadius(&press2, 5, 0);
        DispatchEventUsingWindowDispatcher(&press2);
        EXPECT_FALSE(delegate->pinch_begin());
        EXPECT_EQ(gfx::Rect(101, 196, 105, 10).ToString(),
            delegate->bounding_box().ToString());

        delegate->Reset();

        ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(50, 50), kTouchId,
            tes.LeapForward(40));
        DispatchEventUsingWindowDispatcher(&move1);
        EXPECT_TRUE(delegate->pinch_begin());
        EXPECT_EQ(gfx::Rect(50, 50, 156, 156).ToString(),
            delegate->bounding_box().ToString());

        delegate->Reset();

        // The position doesn't move, but the radius changes.
        ui::TouchEvent move2(
            ui::ET_TOUCH_MOVED, gfx::Point(50, 50), kTouchId, tes.LeapForward(40));
        SetTouchRadius(&move2, 50, 60);
        DispatchEventUsingWindowDispatcher(&move2);
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->pinch_update());

        delegate->Reset();
    }

    // Checks that slow scrolls deliver the correct deltas.
    // In particular, fix for http;//crbug.com/150573.
    TEST_F(GestureRecognizerTest, NoDriftInScroll)
    {
        ui::GestureConfiguration::GetInstance()
            ->set_max_touch_move_in_pixels_for_click(3);
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 234;
        const int kWindowHeight = 345;
        const int kTouchId = 5;
        TimedEvents tes;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        ui::TouchEvent press1(
            ui::ET_TOUCH_PRESSED, gfx::Point(101, 208), kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        EXPECT_TRUE(delegate->begin());

        delegate->Reset();

        ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(101, 206), kTouchId,
            tes.LeapForward(40));
        DispatchEventUsingWindowDispatcher(&move1);
        EXPECT_FALSE(delegate->scroll_begin());

        delegate->Reset();

        ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(101, 204), kTouchId,
            tes.LeapForward(40));
        DispatchEventUsingWindowDispatcher(&move2);
        EXPECT_TRUE(delegate->tap_cancel());
        EXPECT_TRUE(delegate->scroll_begin());
        EXPECT_TRUE(delegate->scroll_update());
        // 3 px consumed by touch slop region.
        EXPECT_EQ(-1, delegate->scroll_y());
        EXPECT_EQ(-4, delegate->scroll_y_hint());

        delegate->Reset();

        ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(101, 204), kTouchId,
            tes.LeapForward(40));
        DispatchEventUsingWindowDispatcher(&move3);
        EXPECT_FALSE(delegate->scroll_update());

        delegate->Reset();

        ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(101, 203), kTouchId,
            tes.LeapForward(40));
        DispatchEventUsingWindowDispatcher(&move4);
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_EQ(-1, delegate->scroll_y());

        delegate->Reset();
    }

    // Ensure that move events which are preventDefaulted will cause a tap
    // cancel gesture event to be fired if the move would normally cause a
    // scroll. See bug http://crbug.com/146397.
    TEST_F(GestureRecognizerTest, GestureEventConsumedTouchMoveCanFireTapCancel)
    {
        scoped_ptr<ConsumesTouchMovesDelegate> delegate(
            new ConsumesTouchMovesDelegate());
        const int kTouchId = 5;
        gfx::Rect bounds(100, 200, 123, 45);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        TimedEvents tes;

        delegate->Reset();
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());

        delegate->set_consume_touch_move(false);
        DispatchEventUsingWindowDispatcher(&press);
        delegate->set_consume_touch_move(true);
        delegate->Reset();
        // Move the touch-point enough so that it would normally be considered a
        // scroll. But since the touch-moves will be consumed, no scrolling should
        // occur.
        // With the unified gesture detector, we will receive a scroll begin gesture,
        // whereas with the aura gesture recognizer we won't.
        tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());
        EXPECT_FALSE(delegate->tap());
        EXPECT_FALSE(delegate->tap_down());
        EXPECT_TRUE(delegate->tap_cancel());
        EXPECT_FALSE(delegate->begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->scroll_end());
    }

    TEST_F(GestureRecognizerTest, CancelAllActiveTouches)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 800;
        const int kWindowHeight = 600;
        const int kTouchId1 = 1;
        const int kTouchId2 = 2;
        gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        scoped_ptr<TestEventHandler> handler(new TestEventHandler());
        window->AddPreTargetHandler(handler.get());

        // Start a gesture sequence on |window|. Then cancel all touches.
        // Make sure |window| receives a touch-cancel event.
        delegate->Reset();
        ui::TouchEvent press(
            ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_2_EVENTS(
            delegate->events(), ui::ET_GESTURE_BEGIN, ui::ET_GESTURE_TAP_DOWN);
        delegate->Reset();
        ui::TouchEvent p2(
            ui::ET_TOUCH_PRESSED, gfx::Point(50, 50), kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&p2);
        EXPECT_2_EVENTS(
            delegate->events(), ui::ET_GESTURE_TAP_CANCEL, ui::ET_GESTURE_BEGIN);
        delegate->Reset();
        ui::TouchEvent move(
            ui::ET_TOUCH_MOVED, gfx::Point(350, 300), kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&move);
        EXPECT_3_EVENTS(delegate->events(),
            ui::ET_GESTURE_SCROLL_BEGIN,
            ui::ET_GESTURE_SCROLL_UPDATE,
            ui::ET_GESTURE_PINCH_BEGIN);
        EXPECT_EQ(2, handler->touch_pressed_count());
        delegate->Reset();
        handler->Reset();

        ui::GestureRecognizer* gesture_recognizer = ui::GestureRecognizer::Get();
        EXPECT_EQ(window.get(),
            gesture_recognizer->GetTouchLockedTarget(press));

        ui::GestureRecognizer::Get()->CancelActiveTouchesExcept(nullptr);

        EXPECT_EQ(NULL, gesture_recognizer->GetTouchLockedTarget(press));
        EXPECT_4_EVENTS(delegate->events(),
            ui::ET_GESTURE_PINCH_END,
            ui::ET_GESTURE_SCROLL_END,
            ui::ET_GESTURE_END,
            ui::ET_GESTURE_END);
        const std::vector<gfx::PointF>& points = handler->cancelled_touch_points();
        EXPECT_EQ(2U, points.size());
        EXPECT_EQ(gfx::PointF(101.f, 201.f), points[0]);
        EXPECT_EQ(gfx::PointF(350.f, 300.f), points[1]);
    }

    // Check that appropriate touch events generate show press events
    TEST_F(GestureRecognizerTest, GestureEventShowPress)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 2;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        EXPECT_TRUE(delegate->tap_down());
        EXPECT_TRUE(delegate->begin());
        EXPECT_FALSE(delegate->tap_cancel());

        // We haven't pressed long enough for a show press to occur
        EXPECT_FALSE(delegate->show_press());

        // Wait until the timer runs out
        delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_SHOW_PRESS);
        EXPECT_TRUE(delegate->show_press());
        EXPECT_FALSE(delegate->tap_cancel());

        delegate->Reset();
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&release1);
        EXPECT_FALSE(delegate->long_press());

        // Note the tap isn't dispatched until the release
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_TRUE(delegate->tap());
    }

    // Check that scrolling cancels a show press
    TEST_F(GestureRecognizerTest, GestureEventShowPressCancelledByScroll)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 6;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        EXPECT_TRUE(delegate->tap_down());

        // We haven't pressed long enough for a show press to occur
        EXPECT_FALSE(delegate->show_press());
        EXPECT_FALSE(delegate->tap_cancel());

        // Scroll around, to cancel the show press
        tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get());
        // Wait until the timer runs out
        DelayByShowPressTimeout();
        EXPECT_FALSE(delegate->show_press());
        EXPECT_TRUE(delegate->tap_cancel());

        delegate->Reset();
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.LeapForward(10));
        DispatchEventUsingWindowDispatcher(&release1);
        EXPECT_FALSE(delegate->show_press());
        EXPECT_FALSE(delegate->tap_cancel());
    }

    // Test that show press events are sent immediately on tap
    TEST_F(GestureRecognizerTest, GestureEventShowPressSentOnTap)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 6;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        EXPECT_TRUE(delegate->tap_down());

        // We haven't pressed long enough for a show press to occur
        EXPECT_FALSE(delegate->show_press());
        EXPECT_FALSE(delegate->tap_cancel());

        delegate->Reset();
        ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release1);
        EXPECT_TRUE(delegate->show_press());
        EXPECT_FALSE(delegate->tap_cancel());
        EXPECT_TRUE(delegate->tap());
    }

    // Test that consuming the first move touch event prevents a scroll.
    TEST_F(GestureRecognizerTest, GestureEventConsumedTouchMoveScrollTest)
    {
        scoped_ptr<QueueTouchEventDelegate> delegate(
            new QueueTouchEventDelegate(host()->dispatcher()));
        TimedEvents tes;
        const int kTouchId = 7;
        gfx::Rect bounds(0, 0, 1000, 1000);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        delegate->set_window(window.get());

        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        delegate->ReceivedAck();

        // A touch move within the slop region is never consumed in web contents. The
        // unified GR won't prevent scroll if a touch move within the slop region is
        // consumed, so make sure this touch move exceeds the slop region.
        ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(10, 10),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&move1);
        delegate->ReceivedAckPreventDefaulted();

        ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(20, 20),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&move2);
        delegate->ReceivedAck();

        // With the unified gesture detector, consuming the first touch move event
        // won't prevent all future scrolling.
        EXPECT_TRUE(delegate->scroll_begin());
        EXPECT_TRUE(delegate->scroll_update());
    }

    // Test that consuming the first move touch doesn't prevent a tap.
    TEST_F(GestureRecognizerTest, GestureEventConsumedTouchMoveTapTest)
    {
        scoped_ptr<QueueTouchEventDelegate> delegate(
            new QueueTouchEventDelegate(host()->dispatcher()));
        TimedEvents tes;
        const int kTouchId = 7;
        gfx::Rect bounds(0, 0, 1000, 1000);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        delegate->set_window(window.get());

        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        delegate->ReceivedAck();

        ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(2, 2),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&move);
        delegate->ReceivedAckPreventDefaulted();

        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(2, 2),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release);
        delegate->ReceivedAck();

        EXPECT_TRUE(delegate->tap());
    }

    // Test that consuming the first move touch doesn't prevent a long press.
    TEST_F(GestureRecognizerTest, GestureEventConsumedTouchMoveLongPressTest)
    {
        scoped_ptr<QueueTouchEventDelegate> delegate(
            new QueueTouchEventDelegate(host()->dispatcher()));
        TimedEvents tes;
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 2;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        delegate->set_window(window.get());

        delegate->Reset();

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        delegate->ReceivedAck();

        ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(103, 203),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&move);
        delegate->ReceivedAckPreventDefaulted();

        // Wait until the timer runs out
        delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_LONG_PRESS);
        EXPECT_TRUE(delegate->long_press());
    }

    // Tests that the deltas are correct when leaving the slop region very slowly.
    TEST_F(GestureRecognizerTest, TestExceedingSlopSlowly)
    {
        ui::GestureConfiguration::GetInstance()
            ->set_max_touch_move_in_pixels_for_click(3);
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        const int kWindowWidth = 234;
        const int kWindowHeight = 345;
        const int kTouchId = 5;
        TimedEvents tes;
        gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        ui::TouchEvent press(
            ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        delegate->Reset();

        ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(11, 10), kTouchId,
            tes.LeapForward(40));
        DispatchEventUsingWindowDispatcher(&move1);
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_EQ(0, delegate->scroll_x());
        EXPECT_EQ(0, delegate->scroll_x_hint());
        delegate->Reset();

        ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(12, 10), kTouchId,
            tes.LeapForward(40));
        DispatchEventUsingWindowDispatcher(&move2);
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_EQ(0, delegate->scroll_x());
        EXPECT_EQ(0, delegate->scroll_x_hint());
        delegate->Reset();

        ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(), kTouchId,
            tes.LeapForward(40));
        move3.set_location_f(gfx::PointF(13.1f, 10.f));
        move3.set_root_location_f(gfx::PointF(13.1f, 10.f));
        DispatchEventUsingWindowDispatcher(&move3);
        EXPECT_TRUE(delegate->scroll_begin());
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_NEAR(0.1, delegate->scroll_x(), 0.0001);
        EXPECT_FLOAT_EQ(3.1f, delegate->scroll_x_hint());
        delegate->Reset();

        ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(14, 10), kTouchId,
            tes.LeapForward(40));
        DispatchEventUsingWindowDispatcher(&move4);
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_NEAR(0.9, delegate->scroll_x(), 0.0001);
        EXPECT_EQ(0.f, delegate->scroll_x_hint());
        delegate->Reset();
    }

    TEST_F(GestureRecognizerTest, ScrollAlternatelyConsumedTest)
    {
        scoped_ptr<QueueTouchEventDelegate> delegate(
            new QueueTouchEventDelegate(host()->dispatcher()));
        TimedEvents tes;
        const int kWindowWidth = 3000;
        const int kWindowHeight = 3000;
        const int kTouchId = 2;
        gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        delegate->set_window(window.get());

        delegate->Reset();

        int x = 0;
        int y = 0;

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(x, y),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        delegate->ReceivedAck();
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        delegate->Reset();

        x += 100;
        y += 100;
        ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(x, y),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&move1);
        delegate->ReceivedAck();
        EXPECT_TRUE(delegate->scroll_begin());
        EXPECT_TRUE(delegate->scroll_update());
        delegate->Reset();

        for (int i = 0; i < 3; ++i) {
            x += 10;
            y += 10;
            ui::TouchEvent move2(
                ui::ET_TOUCH_MOVED, gfx::Point(x, y), kTouchId, tes.Now());
            DispatchEventUsingWindowDispatcher(&move2);
            delegate->ReceivedAck();
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_TRUE(delegate->scroll_update());
            EXPECT_EQ(10, delegate->scroll_x());
            EXPECT_EQ(10, delegate->scroll_y());
            delegate->Reset();

            x += 20;
            y += 20;
            ui::TouchEvent move3(
                ui::ET_TOUCH_MOVED, gfx::Point(x, y), kTouchId, tes.Now());
            DispatchEventUsingWindowDispatcher(&move3);
            delegate->ReceivedAckPreventDefaulted();
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            delegate->Reset();
        }
    }

    TEST_F(GestureRecognizerTest, PinchAlternatelyConsumedTest)
    {
        scoped_ptr<QueueTouchEventDelegate> delegate(
            new QueueTouchEventDelegate(host()->dispatcher()));
        TimedEvents tes;
        const int kWindowWidth = 3000;
        const int kWindowHeight = 3000;
        const int kTouchId1 = 5;
        const int kTouchId2 = 7;
        gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        delegate->set_window(window.get());
        delegate->Reset();

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        delegate->ReceivedAck();
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        delegate->Reset();

        int x = 0;
        int y = 0;

        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(x, y),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);
        delegate->ReceivedAck();
        EXPECT_FALSE(delegate->scroll_begin());
        EXPECT_FALSE(delegate->scroll_update());
        EXPECT_FALSE(delegate->pinch_begin());
        EXPECT_FALSE(delegate->pinch_update());

        delegate->Reset();

        x += 100;
        y += 100;
        ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(x, y),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&move1);
        delegate->ReceivedAck();
        EXPECT_TRUE(delegate->scroll_begin());
        EXPECT_TRUE(delegate->scroll_update());
        EXPECT_TRUE(delegate->pinch_begin());
        EXPECT_FALSE(delegate->pinch_update());
        delegate->Reset();

        const float expected_scales[] = { 1.5f, 1.2f, 1.125f };

        for (int i = 0; i < 3; ++i) {
            x += 50;
            y += 50;
            ui::TouchEvent move2(
                ui::ET_TOUCH_MOVED, gfx::Point(x, y), kTouchId2, tes.Now());
            DispatchEventUsingWindowDispatcher(&move2);
            delegate->ReceivedAck();
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_TRUE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());
            EXPECT_FALSE(delegate->pinch_begin());
            EXPECT_TRUE(delegate->pinch_update());
            EXPECT_FALSE(delegate->pinch_end());
            EXPECT_EQ(25, delegate->scroll_x());
            EXPECT_EQ(25, delegate->scroll_y());
            EXPECT_FLOAT_EQ(expected_scales[i], delegate->scale());
            delegate->Reset();

            x += 100;
            y += 100;
            ui::TouchEvent move3(
                ui::ET_TOUCH_MOVED, gfx::Point(x, y), kTouchId2, tes.Now());
            DispatchEventUsingWindowDispatcher(&move3);
            delegate->ReceivedAckPreventDefaulted();
            EXPECT_FALSE(delegate->scroll_begin());
            EXPECT_FALSE(delegate->scroll_update());
            EXPECT_FALSE(delegate->scroll_end());
            EXPECT_FALSE(delegate->pinch_begin());
            EXPECT_FALSE(delegate->pinch_update());
            EXPECT_FALSE(delegate->pinch_end());
            delegate->Reset();
        }
    }

    // Test that touch event flags are passed through to the gesture event.
    TEST_F(GestureRecognizerTest, GestureEventFlagsPassedFromTouchEvent)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 6;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        delegate->Reset();

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        EXPECT_TRUE(delegate->tap_down());

        int default_flags = delegate->flags();

        ui::TouchEvent move1(
            ui::ET_TOUCH_MOVED, gfx::Point(397, 149), kTouchId, tes.LeapForward(50));
        move1.set_flags(992);

        DispatchEventUsingWindowDispatcher(&move1);
        EXPECT_NE(default_flags, delegate->flags());
    }

    // A delegate that deletes a window on long press.
    class GestureEventDeleteWindowOnLongPress : public GestureEventConsumeDelegate {
    public:
        GestureEventDeleteWindowOnLongPress()
            : window_(NULL)
        {
        }

        void set_window(aura::Window** window) { window_ = window; }

        void OnGestureEvent(ui::GestureEvent* gesture) override
        {
            GestureEventConsumeDelegate::OnGestureEvent(gesture);
            if (gesture->type() != ui::ET_GESTURE_LONG_PRESS)
                return;
            ui::GestureRecognizer::Get()->CleanupStateForConsumer(*window_);
            delete *window_;
            *window_ = NULL;
        }

    private:
        aura::Window** window_;
        DISALLOW_COPY_AND_ASSIGN(GestureEventDeleteWindowOnLongPress);
    };

    // Check that deleting the window in response to a long press gesture doesn't
    // crash.
    TEST_F(GestureRecognizerTest, GestureEventLongPressDeletingWindow)
    {
        GestureEventDeleteWindowOnLongPress delegate;
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId = 2;
        gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight);
        aura::Window* window(CreateTestWindowWithDelegate(
            &delegate, -1234, bounds, root_window()));
        delegate.set_window(&window);

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED,
            gfx::Point(101, 201),
            kTouchId,
            ui::EventTimeForNow());
        DispatchEventUsingWindowDispatcher(&press1);
        EXPECT_TRUE(window != NULL);

        // Wait until the timer runs out.
        delegate.WaitUntilReceivedGesture(ui::ET_GESTURE_LONG_PRESS);
        EXPECT_EQ(NULL, window);
    }

    TEST_F(GestureRecognizerWithSwitchTest, GestureEventSmallPinchDisabled)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 300;
        const int kWindowHeight = 400;
        const int kTouchId1 = 3;
        const int kTouchId2 = 5;
        gfx::Rect bounds(5, 5, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 301),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);

        // Move the first finger.
        delegate->Reset();
        ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(65, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move1);

        EXPECT_3_EVENTS(delegate->events(),
            ui::ET_GESTURE_SCROLL_BEGIN,
            ui::ET_GESTURE_SCROLL_UPDATE,
            ui::ET_GESTURE_PINCH_BEGIN);

        // No pinch update occurs, as kCompensateForUnstablePinchZoom is on and
        // |min_pinch_update_span_delta| was nonzero, and this is a very small pinch.
        delegate->Reset();
        ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(65, 202),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move2);
        EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
    }

    TEST_F(GestureRecognizerTest, GestureEventSmallPinchEnabled)
    {
        scoped_ptr<GestureEventConsumeDelegate> delegate(
            new GestureEventConsumeDelegate());
        TimedEvents tes;
        const int kWindowWidth = 300;
        const int kWindowHeight = 400;
        const int kTouchId1 = 3;
        const int kTouchId2 = 5;
        gfx::Rect bounds(5, 5, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));

        ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 301),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10),
            kTouchId2, tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);

        // Move the first finger.
        delegate->Reset();
        ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(65, 201),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move1);

        EXPECT_3_EVENTS(delegate->events(),
            ui::ET_GESTURE_SCROLL_BEGIN,
            ui::ET_GESTURE_SCROLL_UPDATE,
            ui::ET_GESTURE_PINCH_BEGIN);

        delegate->Reset();
        ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(65, 202),
            kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move2);
        EXPECT_2_EVENTS(delegate->events(),
            ui::ET_GESTURE_SCROLL_UPDATE,
            ui::ET_GESTURE_PINCH_UPDATE);
    }

    // Tests that delaying the ack of a touch release doesn't trigger a long press
    // gesture.
    TEST_F(GestureRecognizerTest, EagerGestureDetection)
    {
        scoped_ptr<QueueTouchEventDelegate> delegate(
            new QueueTouchEventDelegate(host()->dispatcher()));
        TimedEvents tes;
        const int kTouchId = 2;
        gfx::Rect bounds(100, 200, 100, 100);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        delegate->set_window(window.get());

        delegate->Reset();
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201),
            kTouchId, tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201),
            kTouchId, tes.LeapForward(50));
        DispatchEventUsingWindowDispatcher(&release);

        delegate->Reset();
        // Ack the touch press.
        delegate->ReceivedAck();
        EXPECT_TRUE(delegate->tap_down());

        delegate->Reset();
        // Wait until the long press event would fire (if we weren't eager).
        DelayByLongPressTimeout();

        // Ack the touch release.
        delegate->ReceivedAck();
        EXPECT_TRUE(delegate->tap());
        EXPECT_FALSE(delegate->long_press());
    }

    // This tests crbug.com/405519, in which touch events which the gesture detector
    // ignores interfere with gesture recognition.
    TEST_F(GestureRecognizerTest, IgnoredEventsDontBreakGestureRecognition)
    {
        scoped_ptr<QueueTouchEventDelegate> delegate(
            new QueueTouchEventDelegate(host()->dispatcher()));
        TimedEvents tes;
        const int kWindowWidth = 300;
        const int kWindowHeight = 400;
        const int kTouchId1 = 3;
        gfx::Rect bounds(5, 5, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        delegate->set_window(window.get());

        ui::TouchEvent press1(
            ui::ET_TOUCH_PRESSED, gfx::Point(101, 301), kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        delegate->ReceivedAck();

        EXPECT_2_EVENTS(
            delegate->events(), ui::ET_GESTURE_BEGIN, ui::ET_GESTURE_TAP_DOWN);

        // Move the first finger.
        delegate->Reset();
        ui::TouchEvent move1(
            ui::ET_TOUCH_MOVED, gfx::Point(65, 201), kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move1);
        delegate->ReceivedAck();

        EXPECT_3_EVENTS(delegate->events(),
            ui::ET_GESTURE_TAP_CANCEL,
            ui::ET_GESTURE_SCROLL_BEGIN,
            ui::ET_GESTURE_SCROLL_UPDATE);

        delegate->Reset();

        // Send a valid event, but don't ack it.
        ui::TouchEvent move2(
            ui::ET_TOUCH_MOVED, gfx::Point(65, 202), kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move2);
        EXPECT_0_EVENTS(delegate->events());

        // Send a touchmove event at the same location as the previous touchmove
        // event. This shouldn't do anything.
        ui::TouchEvent move3(
            ui::ET_TOUCH_MOVED, gfx::Point(65, 202), kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move3);

        // Ack the previous valid event. The intermediary invalid event shouldn't
        // interfere.
        delegate->ReceivedAck();
        EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);
    }

    // Tests that an event stream can have a mix of sync and async acks.
    TEST_F(GestureRecognizerTest,
        MixedSyncAndAsyncAcksDontCauseOutOfOrderDispatch)
    {
        scoped_ptr<QueueTouchEventDelegate> delegate(
            new QueueTouchEventDelegate(host()->dispatcher()));
        TimedEvents tes;
        const int kWindowWidth = 300;
        const int kWindowHeight = 400;
        const int kTouchId1 = 3;
        gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            delegate.get(), -1234, bounds, root_window()));
        delegate->set_window(window.get());

        // Start a scroll gesture.
        ui::TouchEvent press1(
            ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&press1);
        delegate->ReceivedAck();

        ui::TouchEvent move1(
            ui::ET_TOUCH_MOVED, gfx::Point(100, 100), kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move1);
        delegate->ReceivedAck();

        delegate->Reset();
        // Dispatch a synchronously consumed touch move, which should be ignored.
        delegate->set_synchronous_ack_for_next_event(true);
        ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(200, 200), kTouchId1,
            tes.Now());
        DispatchEventUsingWindowDispatcher(&move2);
        EXPECT_0_EVENTS(delegate->events());

        // Dispatch a touch move, but don't ack it.
        ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(300, 300), kTouchId1,
            tes.Now());
        DispatchEventUsingWindowDispatcher(&move3);

        // Dispatch two synchronously consumed touch moves, which should be ignored.
        delegate->set_synchronous_ack_for_next_event(true);
        ui::TouchEvent move4(
            ui::ET_TOUCH_MOVED, gfx::Point(400, 400), kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move4);

        delegate->set_synchronous_ack_for_next_event(true);
        ui::TouchEvent move5(
            ui::ET_TOUCH_MOVED, gfx::Point(500, 500), kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move5);

        EXPECT_0_EVENTS(delegate->events());
        EXPECT_EQ(100, delegate->bounding_box().x());
        // Ack the pending touch move, and ensure the most recent gesture event
        // used its co-ordinates.
        delegate->ReceivedAck();
        EXPECT_EQ(300, delegate->bounding_box().x());
        EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE);

        // Dispatch a touch move, but don't ack it.
        delegate->Reset();
        ui::TouchEvent move6(ui::ET_TOUCH_MOVED, gfx::Point(600, 600), kTouchId1,
            tes.Now());
        DispatchEventUsingWindowDispatcher(&move6);

        // Dispatch a synchronously unconsumed touch move.
        delegate->set_synchronous_ack_for_next_event(false);
        ui::TouchEvent move7(
            ui::ET_TOUCH_MOVED, gfx::Point(700, 700), kTouchId1, tes.Now());
        DispatchEventUsingWindowDispatcher(&move7);

        // The synchronous ack is stuck behind the pending touch move.
        EXPECT_0_EVENTS(delegate->events());

        delegate->ReceivedAck();
        EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE,
            ui::ET_GESTURE_SCROLL_UPDATE);
    }

    TEST_F(GestureRecognizerTest, GestureEventTwoWindowsActive)
    {
        scoped_ptr<QueueTouchEventDelegate> queued_delegate(
            new QueueTouchEventDelegate(host()->dispatcher()));
        TimedEvents tes;
        const int kWindowWidth = 123;
        const int kWindowHeight = 45;
        const int kTouchId1 = 6;
        const int kTouchId2 = 4;
        gfx::Rect bounds(150, 200, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
            queued_delegate.get(), -1234, bounds, root_window()));
        queued_delegate->set_window(window.get());

        // Touch down on the window. This should not generate any gesture event.
        queued_delegate->Reset();
        ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(151, 201), kTouchId1,
            tes.Now());
        DispatchEventUsingWindowDispatcher(&press);
        EXPECT_FALSE(queued_delegate->tap());
        EXPECT_FALSE(queued_delegate->tap_down());
        EXPECT_FALSE(queued_delegate->tap_cancel());
        EXPECT_FALSE(queued_delegate->begin());
        EXPECT_FALSE(queued_delegate->scroll_begin());
        EXPECT_FALSE(queued_delegate->scroll_update());
        EXPECT_FALSE(queued_delegate->scroll_end());

        // Touch down on the second window. This should not generate any
        // gesture event.
        scoped_ptr<QueueTouchEventDelegate> queued_delegate2(
            new QueueTouchEventDelegate(host()->dispatcher()));
        gfx::Rect bounds2(0, 0, kWindowWidth, kWindowHeight);
        scoped_ptr<aura::Window> window2(CreateTestWindowWithDelegate(
            queued_delegate2.get(), -2345, bounds2, root_window()));
        queued_delegate2->set_window(window2.get());

        queued_delegate2->Reset();
        ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(1, 1), kTouchId2,
            tes.Now());
        DispatchEventUsingWindowDispatcher(&press2);
        EXPECT_FALSE(queued_delegate2->tap());
        EXPECT_FALSE(queued_delegate2->tap_down());
        EXPECT_FALSE(queued_delegate2->tap_cancel());
        EXPECT_FALSE(queued_delegate2->begin());
        EXPECT_FALSE(queued_delegate2->scroll_begin());
        EXPECT_FALSE(queued_delegate2->scroll_update());
        EXPECT_FALSE(queued_delegate2->scroll_end());

        // Ack the first window's touch; make sure it is processed by the first
        // window.
        queued_delegate->Reset();
        queued_delegate->ReceivedAck();
        EXPECT_FALSE(queued_delegate->tap());
        EXPECT_FALSE(queued_delegate->show_press());
        EXPECT_TRUE(queued_delegate->tap_down());
        EXPECT_FALSE(queued_delegate->tap_cancel());
        EXPECT_TRUE(queued_delegate->begin());
        EXPECT_FALSE(queued_delegate->scroll_begin());
        EXPECT_FALSE(queued_delegate->scroll_update());
        EXPECT_FALSE(queued_delegate->scroll_end());
        EXPECT_FALSE(queued_delegate->long_press());

        // Ack the second window's touch; make sure it is processed by the second
        // window.
        queued_delegate2->Reset();
        queued_delegate2->ReceivedAck();
        EXPECT_FALSE(queued_delegate2->tap());
        EXPECT_FALSE(queued_delegate2->show_press());
        EXPECT_TRUE(queued_delegate2->tap_down());
        EXPECT_FALSE(queued_delegate2->tap_cancel());
        EXPECT_TRUE(queued_delegate2->begin());
        EXPECT_FALSE(queued_delegate2->scroll_begin());
        EXPECT_FALSE(queued_delegate2->scroll_update());
        EXPECT_FALSE(queued_delegate2->scroll_end());
        EXPECT_FALSE(queued_delegate2->long_press());

        queued_delegate->Reset();
        queued_delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_SHOW_PRESS);
        EXPECT_TRUE(queued_delegate->show_press());
        EXPECT_FALSE(queued_delegate->tap_down());
    }

} // namespace test
} // namespace aura
